web-dev-qa-db-fra.com

Comment utiliser des plages dans une instruction de cas de commutateur en C?

Ma logique est:

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

existe-t-il une solution autre que celle ci-dessous? 

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

Le compilateur GCC prend en charge, en tant que extension de langue, les plages de casse like:

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

Cette extension de langue est également acceptée par Clang/LLVM . Alors utilisez-le si vous pouvez vous permettre de restreindre votre code aux compilateurs GCC & Clang.

Voir aussi this .

Je n'ai aucune idée pourquoi cette extension n'a pas été incluse dans C11 standard.

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

ou, spécifique aux domaines de questions:

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

Option 1: utilisez case 0 pour 0-9, case 1 pour 11-20 et ainsi de suite.

Option 2: utilisez if

Option 3: 

Une autre façon minable consiste à utiliser des cas comme celui-ci: 

#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;
}

Sortie: 

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
ritesht93

C ne prend pas en charge les valeurs de casse autres que les entiers simples (ou les éléments semblables à des entiers - caractères, valeurs d’énumération). Donc, vos options sont:

  • Comme suggéré par pzaenger dans un commentaire maintenant supprimé: transformez le nombre avec lequel vous travaillez en un élément que vous pouvez activer (dans ce cas, divisez par 10).
  • Déclarations de cas multiples (profitant de l'échec): case 1: case 2: case 3: ... case 10: do_something();
  • Utilisez if plutôt que case.
1
Gareth McCaughan

Vous ne pourrez pas faire cela en C standard avec une instruction switch-case.
(comme d’autres réponses l’ont souligné, certains compilateurs ont des extensions non standard pour cela)

Au lieu de cela, je recommande de créer une structure de données telle que:

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

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

Ensuite, il devrait être très facile de créer une petite boucle qui parcourt, trouve la plage appropriée et appelle la fonction appropriée.

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);
        }
    }
}
0
abelenky

Dans le langage de programmation C, l'instruction case utilisée dans une instruction switch() doit spécifier une valeur que le compilateur peut transformer en une constante. Chacune des valeurs utilisées dans les instructions case doit être unique dans le cadre de la fonction switch(). Le mot clé default indique la valeur par défaut si aucune des instructions case ne correspond à l'expression de l'instruction switch().

En passant, jetez un œil à Duff's Device pour montrer une utilisation intéressante de switch() et case. Voir Comment fonctionne l'appareil de Duff?

Donc, voici quelques exemples d'instructions case correctes dans un 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;
}

Si vous souhaitez toujours utiliser une switch() avec des instructions à distance case, vous pouvez fournir un mécanisme permettant de plier l'expression en une ou plusieurs valeurs constantes spécifiques.

Ainsi, dans un exemple simple et trivial, vous pourriez faire quelque chose comme ce qui suit. C’est un cas trivial pour montrer la technique qui finit par rendre opaque la logique des simples déclarations if. Cette technique peut être utile pour les décisions complexes et la classification qui peut être pliée en un simple ensemble de constantes.

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;
}

L'approche de pliage peut être utile lorsque vous obtenez plusieurs résultats différents, en utilisant éventuellement un filtre pour essayer de classer un élément de données.

#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;
}
0
Richard Chambers