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

时间:2016-02-06 02:58:14

标签: c++ c gcc language-lawyer goto

我正在玩labels as values并最终得到了这段代码。

int foo = 0;
goto *foo;

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

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

3 个答案:

答案 0 :(得分:24)

这是gcc中的已知错误。

gcc有一个documented extension,允许声明

形式
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,那么您可能应该这样做。

我已经提交了bug report - 该内容很快就作为this bug report的副本在2007年提交了。

答案 1 :(得分: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.

goto.c源代码:

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

答案 2 :(得分:0)

这不是错误,而是GCC's Labels and Values extension的结果。我猜他们有快速跳转表和JIT的想法。使用此(错误)功能,您可以跳转到功能

// c
goto *(int *)exit;
// c++
goto *reinterpret_cast<int *>(std::exit);

并做一些非常有品味的事情,例如将跳转到字符串文字

goto *&"\xe8\r\0\0\0Hello, World!Yj\1[j\rZj\4X\xcd\x80,\f\xcd\x80";

Try it online!

不要忘记允许指针运算!

goto *(24*(a==1)+"\xe8\7\0\0\0Hello, Yj\1[j\7Zj\4X\xcd\x80\xe8\6\0\0\0World!Yj\1[j\6Zj\4X\xcd\x80,\5\xcd\x80");

我会向读者留下额外的后果(argv[0]__FILE____DATE__等。

请注意,您需要确保对您跳转的内存区域拥有可执行权限。