4

Consider this C-code, where foo is an int:

switch(foo){
    case 1: {
        int bla = 255;
        case 2:
            printf("case12 %d\n", bla);
        break;
        case 3:
            printf("case3  %d\n", bla);
    }
};

For different values of foo the code gives the following output:

case12 255   # foo=1
case12 255   # foo=2
case3  0     # foo=3

I have a problem understanding foo=3. The line that declares bla and defines its value should not execute, when foo=3. The switch statement should jump right to the label for case 3:. Yet there is no warning, so bla seems to have been declared at least. It might be used uninitialized and its value just happens to be 0, though. Can you explain, what's happening in "case 3", and why this is legal C-code?

con-f-use
  • 3,772
  • 5
  • 39
  • 60

1 Answers1

7

A switch statement is essentially a computed goto. The case labels can appear anywhere within the (usually compound) statement controlled by the switch, even within nested blocks.

The declaration int bla = 255; creates an int object bla whose lifetime is the execution of the enclosing block and whose name is visible from the point of its declaration to the end of the block.

If the switch statement causes control to jump to the case 2: or case 3: label, it jumps into the scope of bla but jumps past its initialization. The value of bla is then garbage (not random, not necessarily 0) and in fact trying to refer to its value has undefined behavior.

You can do the same thing with a goto statement

Don't do that.

(For gcc, you'll get a warning if you compile with -Wall, or -Wextra, or -Wmaybe-uninitialized.)

(For another abuse of the switch statement, see Duff's Device.)

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • Thanks for the answer. I still don't see why the `bla` exists at all. Naively, I'd assume, the declaration would be skipped as well (not just the initialization). But obviously the code provides `bla`. – con-f-use Aug 06 '16 at 23:57
  • 2
    @con-f-use: It exists because control entered the block in which it's defined. Its *lifetime* starts when control reaches (or jumps over) the opening `{` and ends when control reaches the closing `}`. The initialization doesn't occur until control reaches the declaration -- and doesn't occur at all if the declaration is jumped over. (C++ forbids this kind of jump.) – Keith Thompson Aug 07 '16 at 00:04
  • @con-f-use: If the definition of of `bla` would be skipped the code could not compile. As it compiles this proves that `bla` is defined. – alk Aug 07 '16 at 15:02