Подтвердить что ты не робот

'goto * foo', где foo не является указателем. Что это?

Я играл с ярлыками как значения и заканчивал этим кодом.

int foo = 0;
goto *foo;

Мой опыт работы с C/С++ говорит мне, что *foo означает dereference foo и что это не будет компилироваться, потому что foo не является указателем. Но он компилируется. Что это на самом деле делает?

gcc (Ubuntu 4.9.2-0ubuntu1~12.04) 4.9.2, если это важно.

4b9b3361

Ответ 1

Это известная ошибка в gcc.

gcc имеет документальное расширение, которое позволяет выписать форму

goto *ptr;

где ptr может быть любым выражением типа void*. Как часть этого расширения, применение унарного && к имени метки дает адрес метки, типа void*.

В вашем примере:

int foo = 0;
goto *foo;

foo явно имеет тип int, а не тип void*. Значение int может быть преобразовано в void*, но только с явным приведением (за исключением специального случая константы нулевого указателя, которая здесь не применяется).

Выражение *foo само по себе правильно диагностируется как ошибка. И это:

goto *42;

компилируется без ошибок (сгенерированный машинный код выглядит как переход к адресу 42, если я правильно читаю код сборки).

Быстрый эксперимент показывает, что gcc генерирует один и тот же код сборки для

goto *42;

как и для

goto *(void*)42;

Последнее является правильным использованием документированного расширения, и это то, что вам должно быть, если по какой-то причине вы хотите перейти к адресу 42.

Я отправил отчет об ошибке - который был быстро закрыт как дубликат этого отчета об ошибке, представленный в 2007 году.

Ответ 2

Кажется, это ошибка GCC. В качестве сравнения вы можете увидеть clang. Похоже, что это ошибки, которые мы должны ожидать.

$ cc -v
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin15.3.0
Thread model: posix
$ cc goto.c 
goto.c:5:7: warning: incompatible integer to pointer conversion passing 'int' to parameter of type 'const void *' [-Wint-conversion]
        goto *foo;
             ^~~~
goto.c:5:2: error: indirect goto in function with no address-of-label expressions
        goto *foo;
        ^
1 warning and 1 error generated.

goto.c исходный код:

int main(int argc, char const *argv[])
{
    int foo = 0;
    goto *foo;
}