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");