C++ 为什么goto的宏定义会使程序崩溃?

C++ 为什么goto的宏定义会使程序崩溃?,c++,c,macros,goto,C++,C,Macros,Goto,我正在读一篇文章,在其中一个答案中有以下代码 #define goto { int x = *(int *)0; } goto 作者在书中指出,每当一个人试图使用goto语句时,他的程序就会崩溃,我的问题是为什么?根据我的理解,intx=*(int*)0将内存地址前4个字节中的任意内容分配给x,但为什么这肯定会使程序崩溃?仅仅是因为您正在取消引用NULL指针。但是程序是否会崩溃还没有定义。它可能会崩溃,可能不会崩溃,或者做一些奇怪的事情。这只是一种未定义的行为,最好避免。 值得注意的是,got

我正在读一篇文章,在其中一个答案中有以下代码

#define goto { int x = *(int *)0; } goto

作者在书中指出,每当一个人试图使用goto语句时,他的程序就会崩溃,我的问题是为什么?根据我的理解,
intx=*(int*)0
将内存地址前4个字节中的任意内容分配给
x
,但为什么这肯定会使程序崩溃?

仅仅是因为您正在取消引用
NULL
指针。但是程序是否会崩溃还没有定义。它可能会崩溃,可能不会崩溃,或者做一些奇怪的事情。这只是一种未定义的行为,最好避免。

值得注意的是,
goto
并非毫无用处。每一个关键词都有它自己的位置,语言作者和标准委员会的成员都有理由保留它(考虑到语言正在发生一些戏剧性的变化)。如果使用明智,Goto在C和C++中有一个值得的位置。p> 为了说明这是一个UB,我使用VC11编译了 以上代码段处于调试和发布模式。在调试模式下,它崩溃了,但是 在发布模式下,编译器只需优化语句即可 没有撞车


<>在C或C++中,内存地址0表示空指针。取消引用此类指针始终是未定义的行为,在大多数实现中,它会引发分段错误,从而导致程序“崩溃”。

代码在两个方面给出了未定义的行为

首先,重新定义语言关键字本身会产生未定义的行为

第二,正如其他人所说,值为“0”的指针是空指针,取消对它的引用会产生未定义的行为

因此,构造的实际结果是未定义的行为。未定义行为的一个常见症状是程序崩溃。然而,实际上并不保证会发生崩溃。这甚至不是必需的


作为编写宏的“为什么”,该代码的作者显然是“goto is evil”阵营的订阅者,并认为可以任意将他/她不知情的偏见强加给他人。在现实中,
goto
有它的用途,即使替代品通常更可取。即使是Dijkstra(人们经常引用其原著来证明不使用goto)也只是描述了肆意使用的问题,并没有声称应该简单地避免。唐纳德·克努特后来在70年代中期写了一篇关于这个话题的论文,包括使用
goto
有益的例子

这位作者不应该仅仅因为不知道如何使用而编写程序,删除c编程的一个重要部分,比如非常有用的
goto
?而且,如果说它将使程序崩溃,那么它将调用未定义的行为,因此程序的行为是不可预测的。这意味着,当它导致未知问题时,这不会阻止任何事情。所以,如果我是你,我会找一本不同的书。@iharob:这不是某本书的作者所指的,而是一个被高估的答案。有时,当我看到那些毫无意义的答案被否决时,我感到很沮丧community@downvoters:请不要对这个问题投反对票,而是对链接到这个问题的答案投反对票,这是误导性的海报,如OP。如果您觉得必须惩罚使用
goto
,那么不可靠的运行时错误是一种愚蠢的做法。更好:
#define goto@
将强制任何使用
goto
的语法错误。更好的是,您可以在您的编码标准中禁止
goto
s;如果你不能信任你的程序员遵循编码标准,那么你就会遇到更大的问题。转换为
0
的指针类型是一个空指针。它不必是内存地址0。对空指针的解引用是未定义的行为,编译器可以沿着执行的任意行为生成代码。从C++运行时的角度来看,包含值0的指针确实指向地址0,不是吗?我不是在说虚拟地址,可能它太清楚了。不,值0到指针的转换不一定是地址0。在C语言中,这在C常见问题解答的第5节中进行了介绍:(具体请参见5.3和5.5)。在这方面,C++没有任何额外的规则,它会迫使空指针的位模式表示0。再次,当我说一个值为0的指针时,我指的是一个指针,它影响了语言中的0个整数。从语言的角度来看,该值将始终为0,因为您可以使用0检查等式。我从来没有谈到位模式,我只谈到地址0,它与任何底层架构都是不可知的。获取位于地址X的对象的地址会产生一个值为X的指针,因此我的地址和指针值之间是平行的。@rems4e:看起来你把实际地址和虚拟地址混淆了。非常感谢!我想我明白了!将代码更改为
#define goto{int x=*(int volatile*)0;}goto
,以获得更一致的崩溃。