Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I put code outside of cases in a switch?

Tags:

c++

c

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.

like image 703
Peter Avatar asked Mar 13 '15 01:03

Peter


People also ask

What is not allowed in a switch statement?

The switch statement doesn't accept arguments of type long, float, double,boolean or any object besides String.

Does switch case order matter?

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.

Can we use switch without case?

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.


2 Answers

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

like image 112
Ulfalizer Avatar answered Sep 30 '22 16:09

Ulfalizer


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. :)

like image 31
lurker Avatar answered Sep 30 '22 15:09

lurker