我正在玩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
,如果重要的话。
答案 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";
不要忘记允许指针运算!
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__
等。
请注意,您需要确保对您跳转的内存区域拥有可执行权限。