Почему я получаю "метка может быть только частью инструкции, а декларация не является инструкцией", если у меня есть переменная, которая инициализируется после метки?

У меня есть следующий упрощенный код:

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

Я получаю ошибку, потому что новая переменная объявляется после метки. Если я поместил содержимое (в основном инициализацию) после метки в блоке {}, компиляция завершится успешно.

Я думаю, что понимаю причину блокировки в случае переключения, но почему это должно быть применимо в случае метки?

Эта ошибка от компилятора gcc

2 ответа

Решение

Стандарт языка просто не допускает этого. За метками могут следовать только операторы, а объявления не считаются как операторы в C. Самый простой способ обойти это, вставив пустой оператор после вашей метки, что освобождает вас от необходимости отслеживать область действия так, как вам нужно. внутри блока.

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

Это причуда грамматики Си. Ярлык (Cleanup:) не разрешается появляться непосредственно перед объявлением (например, char *str ...;), только перед заявлением (printf(...);). В C89 это не было большой трудностью, потому что объявления могли появляться только в самом начале блока, так что вы всегда могли немного переместить метку вниз и избежать проблемы. В C99 вы можете смешивать объявления и код, но вы все равно не можете поставить метку непосредственно перед объявлением.

Вы можете поставить точку с запятой сразу после двоеточия метки (как предлагает Ренан), чтобы там было пустое утверждение; это то, что я бы сделал в машинно-сгенерированном коде. Либо поднимите объявление в начало функции:

int main (void) 
{
    char *str;
    printf("Hello ");
    goto Cleanup;
Cleanup:
    str = "World\n";
    printf("%s\n", str);
    return 0;
}
Другие вопросы по тегам