Объявление переменной после перехода к метке - PullRequest
66 голосов
/ 05 декабря 2011

Сегодня я нашел одну интересную вещь.Я не знал, что нельзя объявить переменную после метки goto.

Компиляция следующего кода

#include <stdio.h>
int main() {
    int x = 5;
    goto JUMP;
    printf("x is : %d\n",x);
JUMP:
    int a = 0;  <=== giving me all sorts of error..
    printf("%d",a);
}

дает ошибки типа

temp.c: In function ‘main’:
temp.c:7: error: expected expression before ‘int’
temp.c:8: error: ‘a’ undeclared (first use in this function)
temp.c:8: error: (Each undeclared identifier is reported only once
temp.c:8: error: for each function it appears in.)

Теперь, что за этим стоит?Я слышал, что нельзя создавать переменные внутри операторов case переключателя .Поскольку JUMP находится внутри той же области видимости (область видимости основной функции, в моем случае) оператора goto, я считаю, что область действия здесь не является проблемой.Но тогда почему я получаю эту ошибку?

Ответы [ 8 ]

84 голосов
/ 05 декабря 2011

Синтаксис просто не позволяет этого. §6.8.1 Помеченные заявления:

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

Обратите внимание, что нет пункта, который допускает "помеченное объявление". Это просто не часть языка.

Вы можете обойти это, конечно, с пустым утверждением.

JUMP:;
int a = 0;
13 голосов
/ 05 декабря 2011

Вы хотите точку с запятой после метки, как это:

 #include <stdio.h>
 int main() {
     int x = 5;
     goto JUMP;
     printf("x is : %d\n",x);
 JUMP: ;     /// semicolon for empty statement
     int a = 0; 
     printf("%d",a);
 }    

Тогда ваш код правильно компилируется для стандарта C99 с gcc -Wall -std=c99 -c krishna.c (я использую GCC 4.6 на Debian / Sid / AMD64).

6 голосов
/ 05 декабря 2011

Простое объяснение, за исключением того, что в спецификации не сказано, состоит в том, что компилятор ожидает, что код после goto будет являться чем-то, что компилируется в операцию, для которой он может затем вычислить смещение, и начинает работать, потому что объявление переменной не является ' оператор / блок, который он может скомпилировать в такое смещение.

6 голосов
/ 05 декабря 2011

Моя версия gcc (4.4) выдает эту ошибку компиляции:

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

. Это сообщение об ошибке говорит само за себя.

2 голосов
/ 05 декабря 2011

Если вы знаете, почему вы не можете создавать переменные внутри оператора case переключателя, в основном это та же самая причина, почему вы тоже не можете сделать это.Как исправить, вы можете попробовать это,

#include <stdio.h>
int main() {
    int x = 5;
    goto JUMP;
    printf("x is : %d\n",x);
JUMP:
    {                                              //Note this
       int a = 0;  // <=== no more error..
       printf("%d",a);
    }                                             //Note this
}
2 голосов
/ 05 декабря 2011

Ну, во-первых, вы должны быть последовательными.Это либо LABEL, либо label.Во-вторых, метка является частью оператора, и декларация не отвечает описанию в достаточной степени.

Вы можете заменить LABEL: на label: ;, а затем выполнить компиляцию с большей вероятностью.

РЕДАКТИРОВАТЬ: Теперь, когда вы отредактировали свой код, его следует заменить JUMP: на JUMP: ;; -)

1 голос
/ 05 декабря 2011

Это не из-за метки как таковой, а потому, что уже есть операторы (goto и printf).Последний стандарт, похоже, допускает объявления переменных в произвольных местах, но не каждый компилятор полностью соответствует стандарту.Кроме того, идентификаторы чувствительны к регистру в C, и ваша метка должна быть одинаковой в обоих местах.

0 голосов
/ 05 декабря 2011
#include <stdio.h>
int main() {
    int x = 5;
    goto JUMP;
    printf("x is : %d\n",x);
JUMP:
    printf("Do anything after label but dont declare 
    anything. even empty statement will also work 
    because label can only be part of a statement");
    int a = 0;  
    printf("%d",a);
}
...