3

Why does a case statement allow declarations within braces but not without them?

For example, the following is not OK

switch (op->name) {
    case 0:
        int a = 2;
    case 1:  
        int b = 3;
}

But the following is OK:

switch (op->name) {
    case 0: 
       {int a = 2;}
    case 1:  
       {int b = 3;}
}

What does the braces resolve that, without them, a declaration would be ambiguous to the compiler? To me (a beginner in C) it seems like each case statement should have an implied braces until the next case/default/end-of-switch, but that is obviously wrong!

samuelbrody1249
  • 4,379
  • 1
  • 15
  • 58
  • 1
    In C, variables must be declared at the start of a block. Curly braces begin a new block. `case` labels do not create "implied braces". – Raymond Chen Jan 23 '21 at 00:23
  • 2
    *"In C, variables must be declared at the start of a block."* @RaymondChen That was the rule in C89. Not true in C99 and later. – user3386109 Jan 23 '21 at 00:25
  • @user3386109 but they **have** to declared inside the block – 0___________ Jan 23 '21 at 00:32
  • @ samuelbrody1249 You *do* need an opening brace after the `switch` statement in snippets 2 and 3. – user3386109 Jan 23 '21 at 00:45
  • @user3386109 sorry that was a typo -- fixed. – samuelbrody1249 Jan 23 '21 at 00:47
  • Snippet 2 is ok, but snippet 3 results in an error message (at least from clang) at the line that declares `b`. – user3386109 Jan 23 '21 at 00:49
  • @user3386109 yes it seems it errors, I suppose the braces cannot extend beyond a single `case`. Anyways, I've removed that case from the question since it's wrong. – samuelbrody1249 Jan 23 '21 at 00:56
  • @samuelbrody1249 Ok, the question seems in fine shape now. BTW, you *can* "fix" the problem by adding a superfluous semicolon after every `case` statement, e.g. `case 0: ;` My best guess is that the rule about not following a `case` statement with a declaration is due to some nasty corner case in the compiler. – user3386109 Jan 23 '21 at 01:02

3 Answers3

5

Why does a case statement allow declarations within braces but not without them?

My compiler emits this error message:

error: a label can only be part of a statement and a declaration is not a statement

That's pretty clear I think. Labels, including case labels, are not considered independent statements or declarations, but rather components of statements. When control branches to a label, whether via a switch or a goto, it is the statement of which the label is a part to which the program jumps. Not to the label itself, which typically has no runtime representation.

Declarations such as int a; are not statements, and labels cannot be part of declarations. On the other hand, blocks such as { int a; } are statements, and as statements, they can have labels.

There's no fundamental underlying constraint here. It would have been possible for C syntax to have been defined differently, so that both of your examples were valid. It just wasn't.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
3

The reason this is invalid:

switch (op->name) {
    case 0:
        int a = 2;
    case 1:  
        int b = 3;
}

Is because you have a label (in this case a case label) in front of a declaration. A label may only appear before a statement.

Using braces works because they are used to denote a compound statement, which is a particular type of statement, and a statement can immediately precede a label.

Formally, a label is part of a labeled statement. This is spelled out in section 6.8.1 of the C standard:

labeled-statement:
  identifier : statement
  case constant-expression : statement
  default : statement
dbush
  • 205,898
  • 23
  • 218
  • 273
1

Try this, and you'll get no error:

switch (op->name) {
    case 0:; /* <--- that ; is essential, see below */
        int a = 2;
    case 1:; /* <--- the same here. */
        int b = 3;
}

The problem is that the case statement is a special case of statement, but a declaration is not a valid substitute of a statement, so a declaration is not allowed immediately after a case label. But you can always end the case_statement with a semicolon (issuing a null statement), and put your declaration right after it.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31