C++ ';转到*foo';其中foo不是指针。这是什么?
我一直在玩弄这些代码,最终得到了这些代码C++ ';转到*foo';其中foo不是指针。这是什么?,c++,c,gcc,language-lawyer,goto,C++,C,Gcc,Language Lawyer,Goto,我一直在玩弄这些代码,最终得到了这些代码 int foo = 0; goto *foo; 我的C/C++经验告诉我,*foo意味着dereference foo,而这不会编译,因为foo不是指针。但它确实可以编译。这实际上是做什么的 gcc(ubuntu4.9.2-0ubuntu1~12.04)4.9.2,如果重要的话。这是gcc中已知的错误 gcc有一个允许以下格式声明的 goto *ptr; 其中ptr可以是void*类型的任何表达式。作为此扩展的一部分,将一元&&应用于标签名称将生成标
int foo = 0;
goto *foo;
我的C/C++经验告诉我,*foo
意味着dereference foo
,而这不会编译,因为foo
不是指针。但它确实可以编译。这实际上是做什么的
gcc(ubuntu4.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错误。下面是一个铿锵的输出作为比较。看来这些都是我们应该预料到的错误
$ 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;
}
这不是一个bug,而是一个错误的结果。我猜他们脑子里想的是跳远台和准时制。使用此(mis)功能,您可以跳转到函数
// c
goto *(int *)exit;
// c++
goto *reinterpret_cast<int *>(std::exit);
别忘了指针算法是允许的
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]
,\uuuuuuuuuuuu文件
,\uuuuuuu日期
,等等)
请注意,您需要确保对跳转到的内存区域具有可执行权限。这与跳转到
foo
地址相同吗?@Ælex:它不会跳转到foo
的地址;它跳转到foo
中包含的地址。取消引用void*
并不比取消引用int更“正确”。@Leushenko:goto*expr
,其中expr
类型为void*
,是对有文档记录的gcc扩展的有效使用。它在ISO C中无效,但标准明确允许扩展。@Leushenko忽略goto*
扩展,在C中取消引用void*
是完全有效的。在严格符合标准的程序中,它是无用的,因为你唯一能做的事情就是放弃结果,或者从C99开始,立即重新获取它的地址,但没有规定它是无效的。它在C++中是不同的。C++通过将<代码> */COD>限制为对象指针和函数类型指针,使代码> >空> * /代码>无效。这个问题被标记为C和C++。我认为不应该。这就是它引起的混乱。这是一个已知的错误。看我更新的答案。事实上这是一个错误。它被记录为允许goto*ptr代码>其中ptr
属于void*
类型<代码>转到*foo代码>其中foo
类型为int*
违反了gcc自己的扩展文档。请参阅和。@KeithThompson我看到文档在哪里指定标签的地址具有类型void*
,但在哪里指定不允许使用goto*
的非void*
参数?“例如,goto*ptr;
任何类型的表达式void*
都是允许的。”
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");