I've always wondered this - why can't you declare variables after a case label in a switch statement? In C++ you can declare variables pretty much anywhere (and declaring them close to first use is obviously a good thing) but the following still won't work:
switch (val)
{
case VAL:
// This won't work
int newVal = 42;
break;
case ANOTHER_VAL:
...
break;
}
The above gives me the following error (MSC):
initialization of 'newVal' is skipped by 'case' label
This seems to be a limitation in other languages too. Why is this such a problem?
I wrote this answer orginally for this question. However when I finished it I found that answer has been closed. So I posted it here, maybe someone who likes references to standard will find it helpful.
Original Code in question:
There are actually 2 questions:
1. Why can I declare a variable after
case
label?It's because in C++ label has to be in form:
N3337 6.1/1
And in
C++
declaration statement is also considered as statement (as opposed toC
):N3337 6/1:
2. Why can I jump over variable declaration and then use it?
Because: N3337 6.7/3
Since
k
is of scalar type, and is not initialized at point of declaration jumping over it's declaration is possible. This is semantically equivalent:However that wouldn't be possible, if
x
was initialized at point of declaration:Interesting that this is fine:
... but this isn't:
I get that a fix is simple enough, but I'm not understanding yet why the first example doesn't bother the compiler. As was mentioned earlier (2 years earlier hehe), declaration is not what causes the error, even despite the logic. Initialisation is the problem. If the variable is initialised and declared on the different lines, it compiles.
Case
statements are only labels. This means the compiler will interpret this as a jump directly to the label. In C++, the problem here is one of scope. Your curly brackets define the scope as everything inside theswitch
statement. This means that you are left with a scope where a jump will be performed further into the code skipping the initialization. The correct way to handle this is to define a scope specific to thatcase
statement and define your variable within it.Ok. Just to clarify this strictly has nothing to do with the declaration. It relates only to "jumping over the initialization" (ISO C++ '03 6.7/3)
A lot of the posts here have mentioned that jumping over the declaration may result in the variable "not being declared". This is not true. An POD object can be declared without an initializer but it will have an indeterminate value. For example:
Where the object is a non-POD or aggregate the compiler implicitly adds an initializer, and so it is not possible to jump over such a declaration:
This limitation is not limited to the switch statement. It is also an error to use 'goto' to jump over an initialization:
A bit of trivia is that this is a difference between C++ and C. In C, it is not an error to jump over the initialization.
As others have mentioned, the solution is to add a nested block so that the lifetime of the variable is limited to the individual case label.
This question
iswas originally tagged as [C] and [C++] at the same time. The original code is indeed invalid in both C and C++, but for completely different unrelated reasons. I believe this important detail was missed (or obfuscated) by the existing answers.In C++ this code is invalid because the
case ANOTHER_VAL:
label jumps into the scope of variablenewVal
bypassing its initialization. Jumps that bypass initialization of local objects are illegal in C++. This side of the issue is correctly addressed by most answers.However, in C language bypassing variable initialization is not an error. Jumping into the scope of a variable over its initialization is legal in C. It simply means that the variable is left uninitialized. The original code does not compile in C for a completely different reason. Label
case VAL:
in the original code is attached to the declaration of variablenewVal
. In C language declarations are not statements. They cannot be labeled. And this is what causes the error when this code is interpreted as C code.Adding an extra
{}
block fixes both C++ and C problems, even though these problems happen to be very different. On the C++ side it restricts the scope ofnewVal
, making sure thatcase ANOTHER_VAL:
no longer jumps into that scope, which eliminates the C++ issue. On the C side that extra{}
introduces a compound statement, thus making thecase VAL:
label to apply to a statement, which eliminates the C issue.In C case the problem can be easily solved without the
{}
. Just add an empty statement after thecase VAL:
label and the code will become validNote that even though it is now valid from C point of view, it remains invalid from C++ point of view.
Symmetrically, in C++ case the the problem can be easily solved without the
{}
. Just remove the initializer from variable declaration and the code will become validNote that even though it is now valid from C++ point of view, it remains invalid from C point of view.
Most of the replies so far are wrong in one respect: you can declare variables after the case statement, but you can't initialize them:
As previously mentioned, a nice way around this is to use braces to create a scope for your case.