1

Whimsically, I initialized the following array c in a switch statement fully expecting my compiler to say NO you can't do that but much to my surprise it compiled in MSVC, GCC and Clang. Online example

I'm assuming that the standard allows it, in which case my question is why? ... considering that declaration and initialization of non-arrays is NOT allowed in case statements.

int main()
{
    char ch;

    switch( ch )
    {
    case 'x':
        //int a = 42; // NOT OKAY
        break;

    case 'y':
        int b;
        b = 42;    // OKAY

    case 'z':
        int c[2] = { 0 , 1 };  // OKAY (Huh???)
        break;
    };
}
4
  • Why would you expect the compiler to not like that? c is totally valid in the context of switch(ch), but not visible outside.
    – user1357959
    Commented Feb 3, 2016 at 12:38
  • It is OK to define (locally) and initialize an array however you won't be able to use it outside the switch scope... (also int a = 42; should perfectly work) (... no reason to tag C++ here)
    – Alex Lop.
    Commented Feb 3, 2016 at 12:38
  • This is just a MWE. I intend to use c in the case statement.
    – Olumide
    Commented Feb 3, 2016 at 12:40
  • @AlexLop. The question relates to C and C++
    – Olumide
    Commented Feb 3, 2016 at 12:48

3 Answers 3

6

If you change your example to

int main()
{
    char ch;

    switch( ch )
    {
    case 'x':
        int c[2] = { 0 , 1 };
        break;

    case 'z':
        int a = 42;
        break;
    }
}

you'll notice that the error now occurs for the array, but not for the int.

Intialisation is actually allowed for the last case.

The rule is not "you're not allowed to initialise a variable in a case" but "you're not allowed to jump across a variable initialisation."

And it's impossible to jump across the initialisation in the last case.

The reason for the rule is that a variable declared in a case is in scope in the subsequent cases, and jumping to a subsequent case would bypass the initialisation.

This becomes (slightly) clearer if you rewrite as a goto-sequence, as the same rules about scope and initialisation apply:

if (ch == 'x') goto x;
if (ch == 'y') goto y;
if (ch == 'z') goto z;
goto end;
{
  x:
    int a = 42;  // goto y or z breaks this
    goto end;
  y:
    int b;      // uninitialised, so OK
    b = 42;
    goto end;
  z:
    int c[2] = {0, 1};  // No label after this, so can't jump across, so OK
    goto end;
}
end:
2

The compiler would issue an error if a jump to a case label bypassed the initialized array. For example

    switch( ch )
    {
        int c[2] = { 0 , 1 };  // OKAY (Huh???)
    case 'x':
        //int a = 42; // NOT OKAY
        break;

    case 'y':
        int b;
        b = 42;    // OKAY

    case 'z':
//        int c[2] = { 0 , 1 };  // OKAY (Huh???)
        break;
    } 

or

    switch( ch )
    {
    case 'x':
        //int a = 42; // NOT OKAY
        break;

    case 'y':
        int b;
        b = 42;    // OKAY

    case 'z':
        int c[2] = { 0 , 1 };  // OKAY (Huh???)
        break;
    default:
        break;
    } 

However in the original program neither jump bypasses the initialized array.

Here is a more simplified demonstrative program. This will compile successfully

int main() 
{
    goto L1;

    {
        L1:;
        int c[2] = { 0 , 1 };
    }       
}    

while this will issue an error

int main() 
{
    goto L1;

    {
        int c[2] = { 0 , 1 };
        L1:;
    }       
}    
1
  • Nice example with the goto! I see what the committee meant to do by preventing jumps past initializations but its not bullet proof as jumps past deferred initializations are not forbidden.
    – Olumide
    Commented Feb 3, 2016 at 13:16
0

Your array is totally fine where it is. You are declaring (and initializing) it in the lexical scope of switch(ch), where it is allowed to live, be initialized, and be referenced by other operations (after it was declared).

What wouldn't work is referencing it outside of the switch, like so:

switch(ch) {
  ...
  case 'z':
    int c[2] = { 0 , 1 };  // OKAY (Huh???)
    break;
};

some_operation(c);

The only situation in which this would be forbidden would be if you had another case statement that uses the same variable. As case statements are just labels (as pointed out here), you could potentially just skip the initialization of a later-on used variable.

So, the compiler let's you do that as long as you use the variable only in one label, but not in multiple.

Not the answer you're looking for? Browse other questions tagged or ask your own question.