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

'goto *foo' where foo is not a pointer. What is this?

我正在研究 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,如果重要的话。

这是 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 -- which was quickly closed as a duplicate of this bug report,2007 年提交的。

似乎是 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;
}

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

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

并做一些非常有品位的事情,比如跳转 到字符串文字中

goto *&"\xe8\r[=11=][=11=][=11=]Hello, World!Yj[j\rZjX\xcd\x80,\f\xcd\x80";

Try it online!

不要忘记指针运算是允许的!

goto *(24*(a==1)+"\xe8[=12=][=12=][=12=]Hello, Yj[jZjX\xcd\x80\xe8[=12=][=12=][=12=]World!Yj[jZjX\xcd\x80,\xcd\x80");

我将把额外的后果作为练习留给 reader(argv[0]__FILE____DATE__ 等)

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