Assume:
switch ( test ) {
// Set some variables, call some functions ?
int x = 1 ;
int y = function(x) ;
//
case 1 :
// Process for test = 1
...
break;
case 5 :
// Process for test = 5
...
break;
default :
// Process for all other cases.
...
}
Is it 'legal' to execute that extra bit of code I added before the first case
? I've never seen this in examples.
The switch statement doesn't accept arguments of type long, float, double,boolean or any object besides String.
Switch statements are always evaluated from top to bottom. The order of cases does not matter as long as you always have the reserved word “break” at the end of all cases that shouldn't have fall-through.
If there's no default statement, and no case match is found, none of the statements in the switch body get executed. There can be at most one default statement. The default statement doesn't have to come at the end.
First some background on how switch
(really) works:
A switch
is usually thought of as a construct that selects a piece of code to execute depending on the value of some expression, as in
switch (x) {
case 1:
foo();
break;
case 2:
bar();
break;
}
However, it's more accurate to think of a switch
as a form of computed goto
statement. For example, the following is perfectly legal:
switch (x) {
puts("I can't be reached");
case 1:
if (cond) {
case 2:
puts("Either x == 1 && cond, or x == 2");
}
}
Depending on the value of x
, the program will jump to either case 1
or case 2
(or past the switch
if x
is neither 1 nor 2).
Your program will compile as C (with junk values for x
and y
inside the switch
, since the initializations are skipped), but not as C++. The reason is that C++ does not allow a jump to a case
label to cross the initialization of a variable. For simple types like int
, skipping over int x;
is allowed (since no initialization is involved), but not skipping over int x = 1;
.
The main motivation for this difference is probably that letting a jump to a case
label cross an initialization in C++ would be unsafe when constructors are involved. For example, if C++ allowed a case
label to occur after a definition My_class my_object
within some scope, then jumping to that case
label would skip my_object
's constructor but still run its destructor when exiting the scope.
The same restrictions apply to goto
in C++. You can't use it to jump into a block and past a variable initialization.
As a side note, switch
follows the same general syntax as if
and while
. The syntax of if
as given in the C11 standard (ISO/IEC 9899:2011, section 6.8.4) is
if ( expression ) statement
, while the syntax of switch
is
switch ( expression ) statement
The only difference as far as statement is concerned (in C -- C++ adds some more limitations as mentioned above) is that it is allowed to contain case
labels (and break
) for a switch
but not for an if
(unless the if
occurs within a switch
).
Just as with an if
, you can even leave off the braces and write code like the following. (Whether this is unnecessarily confusing is another discussion.)
switch (x) case 1: case 2: puts("x is 1 or 2");
Syntactically, case
and default
labels belong in the same category as goto
labels. Section 6.8.1 of the C11 standard has the following definition:
labeled-statement:
identifier : statement
case constant-expression : statement
default : statement
You can find out what happens with a simple test:
int w = 1;
switch (w)
{
int i = 3;
int y = foo(i);
case 1:
printf("here %d\n", y);
printf("here %d\n", i);
break;
case 2:
printf("not here\n");
break;
}
This code will compile inside of a function using gcc
. The C compiler sees i
and y
declared inside of a block delimited by the braces, so will accept it. However, the printf
statements will print junk for i
and y
, because the assignments are never executed. This is because a switch
statement forms a jump to the case
which corresponds to the expression at the head of the switch
. So the executable code between the opening brace and the first case
cannot be reached. See Why can't variables be declared in a switch statement?, which doesn't explain exactly the same scenario, but does have some related discussion about the switch
statement.
If you compile this with warnings turned on (gcc -Wall
), you get:
foo.c: In function ‘main’:
foo.c:19:15: warning: ‘y’ may be used uninitialized in this function [-Wuninitialized]
foo.c:20:15: warning: ‘i’ may be used uninitialized in this function [-Wuninitialized]
Interestingly, the following code will compile without warnings and work:
int w = 1;
switch (w)
{
int i;
int y;
case 1:
i = 2; y = 3 * i;
printf("here %d\n", y);
printf("here %d\n", i);
break;
case 2:
i = 1; y = 2;
printf("here %d\n", y);
printf("here %d\n", i);
break;
}
The variables print as you would expect them to as they're declared within the scope of the switch
block, and values set within the case
sections where execution occurs. The fact that it works in this case is not to say that it is recommended practice. :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With