‘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__
等等)
请注意,您需要确保对跳转到的内存区域具有可执行权限。