137

I have the following simplified code:

#include <stdio.h>
int main () 
{
    printf("Hello ");
    goto Cleanup;
Cleanup:
    char *str = "World\n";
    printf("%s\n", str);
}

I get an error because a new variable is declared after the label. If I put the content (mainly initialization) after the label in a {} block, compilation succeeds.

I think I understand the reason for the block in case of a switch, but why should it be applicable in case of a label ?

This error is from a gcc compiler

user1952500
  • 6,611
  • 3
  • 24
  • 37
  • 2
    When define a variable below a label, you shall tell the scope of the variable. ``` #include int main () { printf("Hello "); goto Cleanup; Cleanup: { char *str = "World\n"; printf("%s\n", str); } } ``` – Wayne Chen Oct 17 '17 at 02:10

2 Answers2

190

The language standard simply doesn't allow for it. Labels can only be followed by statements, and declarations do not count as statements in C. The easiest way to get around this is by inserting an empty statement after your label, which relieves you from keeping track of the scope the way you would need to inside a block.

#include <stdio.h>
int main () 
{
    printf("Hello ");
    goto Cleanup;
Cleanup: ; //This is an empty statement.
    char *str = "World\n";
    printf("%s\n", str);
}
Renan Gemignani
  • 2,683
  • 1
  • 21
  • 23
  • 27
    Wow, that's bizzare. What's the reason behind that ? – user1952500 Aug 28 '13 at 19:20
  • 42
    Prior to C99, all declarations had to precede all statements within a block, so it wouldn't have made sense to have a label on a declaration. C99 relaxed that restriction, permitting declarations and statement to be mixed within a block, but the syntax of a *labeled-statement* was not changed. – Keith Thompson Aug 28 '13 at 19:21
  • 4
    It's not generally possible to give *reasons* for this kind of language quirk. The grammar is just the way it is. I can look in the C Rationale document ... not till tomorrow, though ... but I probably won't find anything. – zwol Aug 28 '13 at 19:21
  • 1
    @Zack: thanks for mentioning the C Rationale document. It looks interesting. However in section 6.8.6.1 (The goto statement) the example he uses in the latter approach as an approved mechanism should have failed! – user1952500 Aug 28 '13 at 19:33
  • 1
    @zwol thanks, what timezone are you in? I'm asking so we'd know when tomorrow is for you, so we could ping you up in case you would forget. – Hi-Angel Oct 06 '20 at 08:55
  • @Hi-Angel I did look, back in 2013, and I didn't find anything, so I didn't add anything here. – zwol Oct 06 '20 at 12:41
  • @KeithThompson Any glue _why_ the syntax of a labeled-statement was not changed? – pmor Mar 25 '22 at 22:14
  • 1
    @pmor Probably because nobody thought of it or considered it to be worth the effort. It's only a problem if you're using `goto` statements, and the workaround is trivial. There *might* be a change in a future edition of the standard, but I haven't found a proposal. – Keith Thompson Mar 25 '22 at 22:41
  • 2
    It's a problem in `case` statements as well. – Deepstop Jul 13 '23 at 12:42
34

This is a quirk of the C grammar. A label (Cleanup:) is not allowed to appear immediately before a declaration (such as char *str ...;), only before a statement (printf(...);). In C89 this was no great difficulty because declarations could only appear at the very beginning of a block, so you could always move the label down a bit and avoid the issue. In C99 you can mix declarations and code, but you still can't put a label immediately before a declaration.

You can put a semicolon immediately after the label's colon (as suggested by Renan) to make there be an empty statement there; this is what I would do in machine-generated code. Alternatively, hoist the declaration to the top of the function:

int main (void) 
{
    char *str;
    printf("Hello ");
    goto Cleanup;
Cleanup:
    str = "World\n";
    printf("%s\n", str);
    return 0;
}
zwol
  • 135,547
  • 38
  • 252
  • 361