4

I am getting compilation error when compiling below code.

#include <stdio.h>
main()
{
    printf("Hello 123\n");
    goto lab;
    printf("Bye\n");

lab: int a = 10;
     printf("%d\n",a);
}

When i compile this code it is giving

test.c:8: error: a label can only be part of a statement and a declaration is not a statement

Why first part of a label should be a statement and why not a declaration?

Chinna
  • 3,930
  • 4
  • 25
  • 55
  • Another explanation is that this is left over from early C where all declarations had to appear at the front of a braced block. A goto couldn't appear before a declaration in the same block, and a goto from outside the block into a a block that had declarations with initializers produced unspecified behavior. There was more of a reason at that point to distinguish between declarations and statements. Another is that declaration can exist outside functions, but statements cannot. – Mike Housky Nov 07 '13 at 07:04
  • @Mike Housky: I'm not sure what importance you assign to "early C" specifically. It has always been legal to jump over declarations (even initialized ones) in C and it is legal today. A jump into the middle of a block never produced "unspecified behavior" actually, it just left its variables uninitialized. This is how it was back then and this is how it is today. The fact that today you can declare a variable in the middle of the block does not change anything: jumping into the block past that variable leaves it uninitialized. So, nothing really changed from the "early C" times in that regard. – AnT stands with Russia Nov 07 '13 at 07:43

3 Answers3

6

Because this feature is called labeled statement

C11 §6.8.1 Labeled statements

Syntax

labeled-statement:

identifier : statement

case constant-expression : statement

default : statement

A simple fix is to use a null statement (a single semecolon;)

#include <stdio.h>
int main()
{
    printf("Hello 123\n");
    goto lab;
    printf("Bye\n");

lab: ;         //null statement
    int a = 10;
    printf("%d\n",a);
}
Community
  • 1
  • 1
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
5

In c according to spec

§6.8.1 Labeled Statements:

labeled-statement:
    identifier : statement
    case constant-expression : statement
    default : statement

In c there is no clause that allows for a "labeled declaration". Do this and it will work:

#include <stdio.h>
int main()
{
    printf("Hello 123\n");
    goto lab;
    printf("Bye\n");

lab: 
    {//-------------------------------
        int a = 10;//                 | Scope
        printf("%d\n",a);//           |Unknown - adding a semi colon after the label will have a similar effect
    }//-------------------------------
}

A label makes the compiler interpret the label as a jump directly to the label. You will have similar problems int this kind of code as well:

switch (i)
{   
   case 1:  
       // This will NOT work as well
       int a = 10;  
       break;
   case 2:  
       break;
}

Again just add a scope block ({ }) and it would work:

switch (i)
{   
   case 1:  
   // This will work 
   {//-------------------------------
       int a = 10;//                 | Scoping
       break;//                      | Solves the issue here as well
   }//-------------------------------
   case 2:  
       break;
}
Sadique
  • 22,572
  • 7
  • 65
  • 91
  • Sorry, this answer just doesn't make sense. There's no issue with "scope" here - the scope is clearly defined by the enclosing block. The `switch` example is not similar at all. The potential issue with `switch` example is that `case 2` label jumps over the initialization of `a`. This would be an error in C++, but not in C. And this is a C question. So, what does that "this will not work" comment is supposed to mean is not clear to me. What exactly "will not work"? And in the original example labels does not even jump over the initialization. – AnT stands with Russia Nov 07 '13 at 07:12
  • @AndreyT - A similar answer here with 338 votes http://stackoverflow.com/questions/92396/why-cant-variables-be-declared-in-a-switch-statement?answertab=active#tab-top ? I stated what the reason could be for the syntax to be that way – Sadique Nov 07 '13 at 07:14
  • @Acme: The answer with 338 votes applies to C++ and only to C++. The question is mistagged as [C] and [C++] at the same time. The issue described in the question does not exist in C. The fact that nobody noted that [C] tag has no business being there is really strange. Meanwhile, this specific question is a C question. The answer you linked does not apply to C language. – AnT stands with Russia Nov 07 '13 at 07:16
  • @AndreyT - i believe scoping does effect the problem here - for example if i add this statement `printf("\n%d"a);` in the first example i showed after the closing brace below `lab` then it will not even compile. While a semi-colon will allow `a` to be visible below as well. – Sadique Nov 07 '13 at 07:20
  • Again what i am trying to say is what the reason is behind disallowing declarations or uninitialized variables in jump statements. – Sadique Nov 07 '13 at 07:23
  • I don't see any connection to scoping. The original code can be easily fixed by adding a `;` after the label. This does not change anything with regard to scoping (or initialization), but the code begins to compile. For this reason, I don't see how anything like "scoping" can have any relevance here. It is just a historical grammatical quirk that prevents the code from compiling. I.e. historically labels must label statements, but not declarations. That's all there is to it. – AnT stands with Russia Nov 07 '13 at 07:26
  • @AndreyT - I still find giving C/C++ tag difference a weird reason to say that the answer is not related to this question. Whatever be the tag `In c there is no clause that allows for a "labeled declaration"` and in C++ `labeled-declaration is allowed but labeled -initialization is not allowed.` And my motive was to explain this and scoping affects this clearly. – Sadique Nov 07 '13 at 07:29
  • I'm not sure what you mean. In C++ declarations are *statements*, which is why they can be labeled (regardless of whether they contain initialization or not). In C declarations are not statements, which is why they can't be labeled. Meanwhile, the issue illustrated by `switch` is a *completely different* issue. It is not about "labeling initialization", it is about *jumping over* initialization. The latter is an error in C++ and is not an error in C. If you noticed, the "error"/"not error" status is "swapped" between C and C++ for these two issues, emphasizing the fact that they are different. – AnT stands with Russia Nov 07 '13 at 07:34
  • @AndreyT i am not disagreeing to what you are saying regarding the difference in C and C++. Also i got your point. – Sadique Nov 07 '13 at 07:47
  • @Acme: I have to admit that I got confused a bit as well. The `switch` code is invalid in both C and C++., but for *completely different unrelated reasons*. In C++ it is invalid because label `case 2:` jumps over initialization of `a`, which is an error in C++ (but not in C). In C it is invalid because it attempts to put `case 1:` label on a declaration, which is an error in C (but not in C++). The answer you linked (338 votes) addresses the C++ side of the issue. This question is about C side of the issue, which is completely different. – AnT stands with Russia Nov 07 '13 at 07:54
  • @AndreyT - Loved the way you clearly explained it, thanks Andrey :) – Sadique Nov 07 '13 at 07:56
  • Your edited answer still says "The problem here is one of scope." It isn't. – Keith Thompson Nov 07 '13 at 16:41
0

A simple (but ugly) solution:

lab: ; 
int a = 10;

The empty statement makes everything OK.
The line break and the space before ; aren't needed.

ugoren
  • 16,023
  • 3
  • 35
  • 65