46
int value;

const int signalmin = some_function();

switch(value)
{
   case signalmin:
   break;
}

I read the value of some_function and use that int value to do a switch case on. The C99 compiler gives back:

error: case label does not reduce to an integer constant

But I cannot use a #define because the int value is being read before the switch executes.

Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
Jim Clermonts
  • 1,694
  • 8
  • 39
  • 94

6 Answers6

66

switch labels must be constant expressions, they have to be evaluated at compile time. If you want to branch on run-time values, you must use an if.

A const-qualified variable is not a constant expression, it is merely a value you are not allowed to modify.

The form of integer constant expressions is detailed in 6.6 (6) [C99 and the n1570 draft of the C2011 standard]:

6 An integer constant expression shall have integer type and shall only have operands that are integer constants, enumeration constants, character constants, sizeof expressions whose results are integer constants, _Alignof expressions, and floating constants that are the immediate operands of casts. Cast operators in an integer constant expression shall only convert arithmetic types to integer types, except as part of an operand to the sizeof or _Alignof operator.

The restriction that only sizeof expressions whose result is an integer constant are allowed rules out sizeof expressions whose operand is a variable length array.

Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
  • 1
    Well, a `const` is not an integer constant expression, but what about `static const` ? – Cyan Aug 26 '15 at 16:54
  • @Cyan Not in C (last I looked). In other languages, things may be different, . – Daniel Fischer Aug 26 '15 at 17:13
  • It's worth noting that in C++, `const int foo = some_expr;` makes `foo` a constant expression if and only if `some_expr` is a constant expression. (I'm not 100% sure I'm stating the rule entirely correctly.) In C, `const` merely means read-only. – Keith Thompson Jun 11 '19 at 01:52
  • Another edge-case: function addresses are integer constants, but because their values are addresses that are determined by the linker, not the compiler, you cannot compare a function pointer using a switch/case block, even if it is casted to `const unitptr_t`. This applies regardless of whether the function is `static`. – KrisW Sep 01 '22 at 11:56
19

Let me chip in with an example. The following was tested on gcc version 4.6.3 with the flags -std=c99 -pedantic set:

#define SOME_HARDCODED_CONSTANT 0 //good
int foo(int i, int b){
    const int c=0; //bad
    int a=0; //bad

    switch(i){
        case c:     //compile error
        case a:     //compile error.
        case (b+a): //compile error
        case SOME_HARDCODED_CONSTANT: //all good
        case 5: //all good
    }
}

As others have noted, case arguments cannot be evaluated at runtime. Use an if-else block to do that.

rath
  • 3,655
  • 1
  • 40
  • 53
10

In C. all case labels must be compile time constants. In C, the const qualifier does not create a compile-time constant, it merely designates that a run-time variable is read-only.

A switch is not the appropriate control structure for what you're trying to do.

John Bode
  • 119,563
  • 19
  • 122
  • 198
2

I am using the code below, and it is working fine.

I am getting an error using case "+": i.e. with double-quotes, so try writing case '+': with single quotes.

#include <stdio.h>

int main() {
    char x;
    int a = 20, b = 10;
    scanf("%c", &x);
    switch (x) {
        case '+':
            printf("%d", a + b);
            break;
        case '-':
            printf("%d", a - b);
            break;
        case '*':
            printf("%d", a * b);
            break;
        case '/':
            printf("%d", a / b);
            break;
        default:
            printf("sorry");
    }
    return 0;
}

trxgnyp1
  • 317
  • 1
  • 10
  • You get an error using `"+"` because that is actually a string literal consisting of the `'+'` character and a NULL terminator. On the other hand, `'+'` evaluates to 43, the code for that character in the ASCII table, which is a constant known at compile time. Your answer has nothing to do with the question. – trxgnyp1 Apr 20 '23 at 19:09
0

In C, variables aren't to be used in the switch case labels instead constant expressions are only allowed there.

0

On OSX, clang seems to take constants as case labels without complaints.

#include <stdio.h>

#define SOME_HARDCODED_CONSTANT 0 //good for sure
int foo(int i, int b){ 
    const int c=1; //no problem!!!

    switch(i){
        case SOME_HARDCODED_CONSTANT: //all good
            printf("case SOME_HARDCODED_CONSTANT\n"); break;
        case c:     //no compile error for clang
            printf("case c\n"); break;
        case 5: //all good
            printf("case 5\n"); break;
    }   
    return i+b;
}

int main() {
    printf("test foo(1,3): %d\n", foo(1,3));
}

Output:

$> cc test.c -o test; ./test 
case c
test foo(1,3): 4
Farley
  • 1,160
  • 1
  • 10
  • 17
  • 1
    It does complain if you ask it to: `caseconst.c:10:14: warning: expression is not an integer constant expression; folding it to a constant is a GNU extension [-Wgnu-folding-constant]`. Here, `const int c = 1;` lets the compiler know the value (as an integer constant expression) at compile time, hence it is possible for it to treat `c` as if it were an integer constant expression in the `switch`. If you initialise `c` with a function call, expect a compile error. – Daniel Fischer Jun 04 '15 at 08:41
  • You may use a different version. My cc complains nothing and reports version as follows. $> cc --version $> Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn) $> Target: x86_64-apple-darwin14.3.0 – Farley Jun 06 '15 at 00:46
  • Yes, a different version. Nevertheless, when you request it to be picky, it must warn, `-std=c11 -Weverything` must tell you about it, also `-Wgnu-folding-constant`, `-pedantic-errors` must lead to a compile error. But since it's a rather harmless thing, you need to tell the compiler to be really picky before it mentions it. – Daniel Fischer Jun 06 '15 at 10:51
  • The picky thing is not always necessary. Constant folding/propagation is quite fundamental for a decent compiler to figure out whether the case label is constant or not regardless of declarations. In this case, the warning is clearly not necessary by default with explicit constant declarations unless users ask for it. – Farley Jun 06 '15 at 16:24
  • Yes, that's why the compiler only complains when you ask it to. My point is that it's not valid code by the language standard, and therefore the compiler is required to issue a diagnostic message (when compiling in compliant mode), even when it accepts the code (with which there's nothing wrong). And it's good to let the compiler be picky, since that tells you about non-portable code, and you can make an informed decision whether you keep the code as is or rewrite it to be portable. – Daniel Fischer Jun 06 '15 at 17:40