2

I was wondering about the possibility of creating an if statement that is more scalable. In the case we have a condition that one variable can possibly be one of many different values for the if statement to be satisfied, I have tried these such formats:

This is the default answer.

if (variable == 23
    || variable == 52 
    || variable == 58 
    || variable == 62 
    || variable == 93)
{ 
    some function
} 

This is what I imagined would work as a newb to C.

if (variable == (23,52,58,62,93) 
{
    some function
}

However, using the comma method I get a warning such that

warning: expression result unused [-Wunused-value]

Does anyone have a possible way to make an if statement of one variable with multiple possible conditions to be written without copy and pasting the variable name each time?

ebehr
  • 167
  • 6
  • 3
    Make a function you can call to get the true/false result. Use an array as a lookup table. Many options to make this cleaner. – Retired Ninja Aug 01 '19 at 02:16
  • 1
    If you use the comma operator, then the value in the last one so essentially, you are comparing `variable` with the value **93**. – Phil1970 Aug 01 '19 at 03:13
  • 2
    That is called `switch`. – user253751 Aug 01 '19 at 03:58
  • @Phil1970 you are on the dot, but why would the comma cause the first 4 values to be ignored? – ebehr Aug 01 '19 at 07:04
  • @ebehr Comma operator allow to write complex expression that are executed from left to right. However, they are rarely used in practice as it make the code harder to read that using separated statements on multiple lines, You might do something like `x = ++p, *p` for example where `p` would be a pointer. Thus `p` would be incremented (point to next value) and then `*p` would be assigned to x. – Phil1970 Aug 01 '19 at 12:46

2 Answers2

5

You can use a switch to check the value of a variable against constant expressions. Here we take advantage of "fall through" from one matched case to the next.

switch(variable) {
    case 23:
    case 52:
    case 58:
    case 62:
    case 93:
        printf("Match!\n");
        break;
    default:
        printf("No match.\n");
}

Note that this will only work with "integral types", that is integers including char and pointers. It will not work with floats nor strings.

Since they do the same thing, a good optimizing compiler will compile if (variable == 23 || variable == 52 || ... ) and the equivalent switch to the same machine code and they will perform exactly the same.

Schwern
  • 153,029
  • 25
  • 195
  • 336
  • 1
    Yes, fall-through! But this also assumes that `variable` is of integral type (e.g. int or char), right? – TrebledJ Aug 01 '19 at 02:24
  • I hope switch statements are faster than if .. else statements. – Austin Aug 01 '19 at 03:27
  • 2
    @Austin it should be the same, that's what compilers do – M.M Aug 01 '19 at 03:29
  • Pedantry alert! Technically, this is not "fall-through"; it's a statement with multiple labels, which is part of the C syntax. Fall-through would require actual statements such as `case 23:; case 52:; ...`. (Those statements are empty, which is a valid C statement. But note that a comment is not a statement, although of course it can appear in an empty statement. So `case 23: /* case 23 */ case 52: /*case 52 */ case 58: ... puts("Match!");` is still one statement with several labels.) – rici Aug 01 '19 at 05:24
  • 1
    @Austin: they often are. The compiler might produce a hard-coded binary search, or it might even compile an indexed jump statement if the alternatives are dense enough. Normally, a linear chain of comparisons will only be produced if there are only a couple of alternatives. – rici Aug 01 '19 at 05:27
  • @Austin In this case with `clang -O3` (and `int variable = getchar();` so the optimizer doesn't get over ambitious) they [compile to the same code](https://gist.github.com/schwern/f6e0b016658d9239b4a1e017440dacdd). – Schwern Aug 01 '19 at 06:00
-2

Updated answer for C

I didn't notice the C tag, so here is an updated answer

int data[] = { 23, 52, 58, 62, 93 };

int found = 0;
for (int i = 0; i != sizeof data / sizeof *data; ++i)
{
    if (data[i] == variable) 
    {
        found = 1;
        break;
    }
}

As with my original C++ answer, you can put the code in a function. However, if the array differ from calling points, you would need to pass a pointer to the start of the array and its size.

Original answer (C++):

Something like:

int data[] = { 23, 52, 58, 62, 93 };

if (std::find(std::begin(data), std::end(data), variable) != std::end(data))
    printf("Match!\n");
else
    printf("No match.\n");

would do the trick.

An improvement would be to put that in a function:

bool find_match(int variable) const // const only for member function
{
    static int data[] = { 23, 52, 58, 62, 93 }; // remove static if data can change.
    return std::find(std::begin(data), std::end(data), variable) != std::end(data);
}
Phil1970
  • 2,605
  • 2
  • 14
  • 15
  • 4
    This is a C question – M.M Aug 01 '19 at 03:29
  • And if it's in C++ then a std::unordered_set would be much better – phuclv Aug 01 '19 at 05:30
  • 1
    @phuclv Or you can just write a small, zero-overhead function in C++17: https://stackoverflow.com/a/15181949/856199 – Nikos C. Aug 01 '19 at 12:52
  • @phuclv Well if you only have a few simple values to tests, you won't have any speed improvement by using hashing or sorting. Using an array improve cache locality. – Phil1970 Aug 01 '19 at 13:02
  • arrays aren't good in this case. Compilers may use a lookup table for cases like this, sometimes even use a bit-lookup table. Just remove 93 in the list and you'll see them compiled to a `BT` instruction – phuclv Aug 01 '19 at 13:24
  • can't upvote cuz of my rep lol (new to programming) but I do enjoy this unique approach to my question. thanks a lot – ebehr Aug 01 '19 at 14:18