How can I use ranges in a switch case statement in C?

末鹿安然 提交于 2019-11-27 02:52:23

问题


My logic is:

if number is between 1 to 10, execute first case statement
if number is from 20 to 30, execute second case statement

is there a solution other than the one below?

case '1' ... '10':
case '20' ... '30':

回答1:


The GCC compiler supports, as a language extension, case ranges like:

 switch(i) {
    case 0 ... 9: return true;
    default: return false;
 }

This language extension is also accepted by Clang/LLVM. So use it if you can afford restricting your code to GCC & Clang compilers.

See also this.

I have no idea why this extension was not included in C11 standard.




回答2:


void SwitchDemo(int value)
   {
   switch(value / 10)
      {
      case 0: ...; break; // 0 - 9
      case 1: ...; break; // 10 - 19
      ...
      }
   }

or, specific to the question ranges:

void SwitchDemo(int value)
   {
   switch((value-1) / 10)
      {
      case 0: ...; break; // 1 - 10
      case 1: ...; break; // 11 - 20
      ...
      }
   }



回答3:


Option 1: use case 0 for 0-9, case 1 for 11-20 and so on.

Option 2: use if

Option 3:

Another shabby way is using fall through cases like this:

#include <stdio.h>

int main(void) {
    int i=1;

    for(i=1;i<=25;i++)
    {
    switch(i)
    {
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
        case 6:
        case 7:
        case 8:
        case 9:
        case 10:
            printf("%d  is in between 1-10\n", i);
            break;

        case 11:
        case 12:
        case 13:
        case 14:
        case 15:
        case 16:
        case 17:
        case 18:
        case 19:
        case 20:
            printf("%d  is in between 11-20\n", i);
            break;

        default:
            printf("%d  is above 20\n", i);
    }
    }
    return 0;
}

Output:

1  is in between 1-10
2  is in between 1-10
3  is in between 1-10
4  is in between 1-10
5  is in between 1-10
6  is in between 1-10
7  is in between 1-10
8  is in between 1-10
9  is in between 1-10
10  is in between 1-10
11  is in between 11-20
12  is in between 11-20
13  is in between 11-20
14  is in between 11-20
15  is in between 11-20
16  is in between 11-20
17  is in between 11-20
18  is in between 11-20
19  is in between 11-20
20  is in between 11-20
21  is above 20
22  is above 20
23  is above 20
24  is above 20
25  is above 20

https://ideone.com/Cw6HDO




回答4:


C doesn't support case values other than single integers (or integer-like things -- characters, enumeration values). So your options are:

  • As suggested by pzaenger in a now-deleted comment: transform the number you're working with into something you can switch on (in this case, divide by 10).
  • Multiple case statements (taking advantage of fallthrough): case 1: case 2: case 3: ... case 10: do_something();
  • Use if rather than case.



回答5:


You won't be able to do this in standard C with a switch-case statement.
(as other answers have pointed out, some compiler have non-standard extensions to enable this)

Instead, I recommend making a data-structure such as:

struct RangeData
{
    int start;
    int end;
    void (*func)(int);
};

RangeData ranges[] = { {   1,    10, Handle10s       }, 
                       {  20,    30, Handle20s       },
                       {5000, 10000, HandleBigNumbers} };

Then it should be very easy to make a tiny loop that cycles through, finds the proper range, and calls the proper function.

void DoNumber(int value)
{
    for(int i=0; i<ARRAYSIZE(ranges); ++i)
    {
        if (ranges[i].start <= value && value <= ranges[i].end)
        {
            ranges[i].func(value);
        }
    }
}



回答6:


In the C programming language the case statement used in a switch() statement must specify a value that the compiler can turn into a constant in some way. Each of the values used in the case statements must be unique within the scope of the switch(). The default keyword indicates the default if none of the case statements match the expression in the switch() statement.

As an aside, check out Duff's Device to show an interesting use of switch() and case. See How does Duff's device work?

So the following shows several examples of proper case statements in a switch():

#define XXVAL 2
#define CASETEST(x) (x + 5)

int iValue;
//  set the value of the variable iValue at some point
switch (iValue) {
case 0:
    // do the case if iValue == 0
    break;
case XXVAL:
    // do the case if iValue == XXVAL
    break;
case CASETEST(3):
    // do the case if iValue == CASETEST(3)
    // works because preprocessor generates the source text which is
    // then compiled and the expression can be resolved to a constant
    break;
case CASETEST(5) * 2:
    // do the case if iValue == CASETEST(5) * 2
    // works because preprocessor generates the source text which is
    // then compiled and the expression can be resolved to a constant
    break;
default:
    break;
}

What you can do if you still want to use a switch() with ranged case statements is to provide some mechanism to fold the expression into one or more specific constant values.

So in a simple, trivial example you could do something like the following. This is a trivial case to show the technique which ends up making the logic of the simple if statements opaque. This technique can be useful for complex decisions and classification that can be folded into a simple set of constants.

int foldit (int iValue)
{
    if (iValue < 5000) return 0;
    else if (iValue < 10000) return 1;
    else if (ivalue < 20000) return 2;
    else return 9999;   // triggers the default part of the switch
}

switch (foldit(iValue)) {
case 0:
    // do what is needed for up to but not including 5000
    break;
case 1:
    // do what is needed for 5000 up to but not including 10000
    break;
case 2:
    // do what is needed for 10000 up to but not including 20000
    break;
default:
    // handle anything else
    break;
}

Where the fold approach can be helpful is when you have several different results perhaps using a filter to try to classify a data item.

#define type1  0x00001
#define type2  0x00002
#define type3  0x00004
#define type4  0x00008

struct datatype {
    int iVal;
    int jVal; 
};

unsigned long is_a_type1(struct datatype * thing)
{
    unsigned long retVal = 0;   // initialize to not a type1, set to type1 if turns out to be
    // do checks for the type and if so set retVal to type1 if it matches
    return retVal;
}

unsigned long is_a_type2(struct datatype * thing)
{
    unsigned long retVal = 0;   // initialize to not a type2, set to type2 if turns out to be
    // do checks for the type and if so set retVal to type2 if it matches
    return retVal;
}

unsigned long is_a_type3(struct datatype * thing)
{
    unsigned long retVal = 0;   // initialize to not a type3, set to type3 if turns out to be
    // do checks for the type and if so set retVal to type3 if it matches
    return retVal;
}

unsigned long is_a_type4(struct datatype * thing)
{
    unsigned long retVal = 0;   // initialize to not a type4, set to type4 if turns out to be
    // do checks for the type and if so set retVal to type4 if it matches
    return retVal;
}

unsigned long classify (struct datatype *thing)
{
    unsigned long ulTestResult = 0;

    // test to see if this is a type1 thing
    ulTestResult |= is_a_type1(thing);

    // test to see if this is a type2 thing
    ulTestResult |= is_a_type2(thing);

    // test to see if this is a type3 thing
    ulTestResult |= is_a_type3(thing);

    // test to see if this is a type4 thing
    ulTestResult |= is_a_type4(thing);

    return ulTestResult;
}

int main ()
{
    struct datatype myThing;
    //  other source code then
    switch (classify(&myThing)) {
    case type1 | type2 | type3:
        // do stuff if this is a type1, type2, and type3 but not type4
        // that is classify() determined that myThing matched all three types.
        break;
    case type1:
        // do stuff if type1 which includes stuff you do for type2 as well under
        // special values of myThing.
        if (myThing.iVal < 50) {
            case type2:
                // at this point we have type2 case stuff that we do. Code above is skipped
                // and the switch () will jump straight to here if classify() is type2.
                //
                // Also stuff we do if type1 and myThing.iVal < 50
                // in other words this code is execute if classify(&myThing) is type2 or
                // if classify(&myThink) is type1 and there is a special processing for myThing.iVal < 50
                break;  // if classify() type2 or if classify() type1 and myThing.ival < 50
            }
        // do stuff if only type1 and myThing.iVal >= 50
        break;
    case type2 | type3:
        // do stuff if type2 and type3 matched but none of the others.
        break;
    default:
        // any other case
        break;
    }
    return 0;
}



回答7:


Switch statements in c can only operate on a constant expression, the case statements cannot include dynamic comparisons.

Example of something which is, and is not, a "Constant Expression" in C?

For something this simple an if/else structure could be clearer and simpler, depending on the compiler your case statement may be translated into a series of branching comparison statements anyways.



来源:https://stackoverflow.com/questions/36748934/how-can-i-use-ranges-in-a-switch-case-statement-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!