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

我正在玩标签作为值 ,最后得到这个代码。

int foo = 0; goto *foo; 

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

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

这是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年提交的此错误报告的副本。

似乎是一个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标签和值扩展的结果 。 我猜他们有快速跳转表和JIT的想法。 使用此(错误)function,您可以跳转到function

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

并做一些非常有品味的事情,比如跳进一个字符串文字

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

在线尝试!

不要忘记允许指针算术!

 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__ __FILE____DATE__等等)

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