为什么goto这个宏定义会导致程序崩溃?

Why this macro define of goto will crash the program?

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

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

作者说每次有人尝试使用 goto 语句时,他的程序都会崩溃,我的问题是为什么?按照我的理解,int x = *(int *)0;是把内存地址的前4个字节的whatever内容赋值给x,但是为什么这样肯定会导致程序崩溃呢?

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

值得注意的是,goto并不是那么无用。每个关键字都有自己的位置,语言作者和标准委员会成员有理由继续维护它(考虑到语言正在发生一些巨大的变化)。如果使用得当,goto 在 C 和 C++ 中占有一席之地。

Just to give an idea how this is an UB, using VC11, I compiled the above snippet in debug and release mode. In debug mode it crashed but in release mode, compiler simply optimized out the statement and there was no crash.

在C或C++中,内存地址0代表一个NULL指针。取消引用这样的指针始终是未定义的行为,并且在大多数实现中它会引发分段错误,有效地 "crashing" 程序。

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

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

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

构造的实际结果因此是未定义的行为。未定义行为的常见症状是程序崩溃。但是,实际上并不能保证崩溃。甚至不需要。

作为编写宏的"why?",该代码的作者显然是"goto is evil"阵营的订阅者,并认为可以任意对his/her造成不知情的偏见其他。实际上,goto 有其用途,即使替代方案通常更可取。甚至 Dijkstra(人们经常引用原论文来证明不使用 goto 的作者)也只是描述了无节制使用的问题,并没有声称应该简单地避免它。 Donald Knuth 后来在 70 年代中期写了一篇关于该主题的论文,其中包括使用 goto 有益的示例。