'goto*foo'其中foo不是指针.这是什么?

Sar*_*adi 24 c c++ gcc goto language-lawyer

我正在玩标签作为值,并最终得到这个代码.

int foo = 0;
goto *foo;
Run Code Online (Sandbox Code Playgroud)

我的C/C++经验告诉我*foo手段dereference foo,这不会编译因为foo不是指针.但它确实编译.这实际上是做什么的?

gcc (Ubuntu 4.9.2-0ubuntu1~12.04) 4.9.2,如果重要的话.

Kei*_*son 24

这是gcc中的已知错误.

gcc有一个记录的扩展,允许声明表单

goto *ptr;
Run Code Online (Sandbox Code Playgroud)

哪里ptr可以是任何类型的表达式void*.作为此扩展的一部分,将一元&&应用于标签名称会生成标签的类型地址void*.

在你的例子中:

int foo = 0;
goto *foo;
Run Code Online (Sandbox Code Playgroud)

foo显然是类型int,而不是类型void*.一个int值可以转换到void*,但只有有明确的转换(除了一个空指针常数,在这里不适用的特殊情况).

表达式*foo本身被正确诊断为错误.还有这个:

goto *42;
Run Code Online (Sandbox Code Playgroud)

编译没有错误(42如果我正确读取汇编代码,生成的机器代码似乎是跳转到地址).

一个快速实验表明gcc生成相同的汇编代码

goto *42;
Run Code Online (Sandbox Code Playgroud)

就像它一样

goto *(void*)42;
Run Code Online (Sandbox Code Playgroud)

后者是对文档扩展的正确使用,如果由于某种原因,你想要跳转到地址42,那么你可能应该这样做.

我已经提交了一份错误报告 - 该报告很快被关闭,作为2007年提交的此错误报告的副本.

  • @Leushenko忽略`goto*`扩展,取消引用`void*`在C中是完全有效的.它在严格符合程序中是无用的,因为你可以对结果做的唯一事情是丢弃结果,或者立即从C99开始再次拿到它的地址,但没有规则说这是无效的.它在C++中有所不同.C++通过将`*`限制为指向对象的指针和指向函数的类型来使取消引用`void*`无效.这个问题被标记为C和C++.我认为不应该这样.这是它引起的那种混乱. (2认同)

Lui*_*ier 6

似乎是一个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.
Run Code Online (Sandbox Code Playgroud)

goto.c 源代码:

int main(int argc, char const *argv[])
{
    int foo = 0;
    goto *foo;
}
Run Code Online (Sandbox Code Playgroud)