web-dev-qa-db-ja.com

Cのswitch caseステートメントで範囲を使用するにはどうすればよいですか?

私の論理は:

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

以下のもの以外の解決策はありますか?

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

[〜#〜] gcc [〜#〜] コンパイラは、言語拡張としてcase範囲 のような:

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

この言語拡張は Clang/LLVM でも受け入れられます。したがって、コードをGCCおよびClangコンパイラーに制限する余裕がある場合に使用してください。

this もご覧ください。

この拡張機能が C11 標準に含まれていなかった理由がわかりません。

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

または、質問の範囲に固有:

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

オプション1:case 0には0-9case 1には11-20などを使用します。

オプション2:ifを使用

オプション3:

別のみすぼらしい方法は、このようなフォールスルーケースを使用することです:

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

出力:

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は、単一の整数(または整数のようなもの-文字、列挙値)以外のケース値をサポートしていません。オプションは次のとおりです。

  • 削除されたコメントでpzaengerが示唆しているように、作業中の番号をcanスイッチオンに変換します(この場合は10で除算します)。
  • 複数のcaseステートメント(フォールスルーを活用):case 1: case 2: case 3: ... case 10: do_something();
  • ifではなくcaseを使用します。
1

switch-caseステートメントを使用して標準Cでこれを行うことはできません。
(他の回答が指摘したように、一部のコンパイラはこれを有効にする非標準の拡張機能を持っています)

代わりに、次のようなデータ構造を作成することをお勧めします。

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

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

その後、循環して適切な範囲を見つけ、適切な関数を呼び出す小さなループを作成するのは非常に簡単です。

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

Cプログラミング言語では、switch()ステートメントで使用されるcaseステートメントは、コンパイラーが何らかの方法で定数に変換できる値を指定する必要があります。 caseステートメントで使用される各値は、switch()のスコープ内で一意でなければなりません。 defaultキーワードは、caseステートメントがswitch()ステートメントの式に一致しない場合のデフォルトを示します。

余談ですが、switch()caseの興味深い使用法を示すために、Duffのデバイスをチェックしてください。 Duffのデバイスはどのように機能しますか?

したがって、以下はswitch()内の適切なcaseステートメントの例をいくつか示しています。

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

範囲のcaseステートメントでswitch()を使用したい場合にできることは、式を1つ以上の特定の定数値にフォールドするメカニズムを提供することです。

そのため、単純で些細な例では、次のようなことができます。これは、単純なifステートメントのロジックを不透明にするテクニックを示す簡単なケースです。この手法は、単純な定数のセットにまとめることができる複雑な決定と分類に役立ちます。

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

フォールドアプローチが役立つのは、フィルターを使用してデータアイテムを分類しようといくつかの異なる結果が得られる場合です。

_#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