我知道当你在C程序中做某些事情时,结果是不确定的。但是,编译器不应该生成无效(机器)代码,对吧?如果代码做错了,或者代码生成了段错误或其他东西,那将是合理的......
这应该根据编译器规范发生,还是编译器中的错误?
这是我使用的(简单)程序:
int main() {
char *ptr = 0;
*(ptr) = 0;
}
我正在使用-O3
进行编译。那不应该生成无效的硬件指令,对吗?使用-O0
,我在运行代码时遇到段错误。这看起来更加明智。
编辑:它生成ud2
指令......
答案 0 :(得分:12)
ud2指令是&#34;有效指令&#34; ,它代表未定义指令并生成无效操作码< / em>异常clang,显然gcc可以在程序调用未定义的行为时生成此代码。
从上面clang
链接的理由解释如下:
存储为null并通过空指针调用转换为 __builtin_trap()调用(变为陷阱指令,如&#34; ud2&#34;在x86上)。这些在优化的代码中始终发生(如 其他转换的结果,如内联和常量 我们过去只删除包含它们的块 因为他们显然无法到达&#34;。
虽然(从迂腐的语言律师的角度来看)这是严格的 是的,我们很快就知道人们偶尔会取消引用null 指针,并且代码执行只是落在了顶部 下一个功能使得理解问题非常困难。从 性能角度,暴露这些的最重要的方面是 压缩下游代码。因此,clang将这些变成了一个 运行时陷阱:如果其中一个实际上是动态到达的,那么 程序立即停止并可以调试。做的缺点 这就是我们通过这些操作来略微膨胀代码 具有控制其谓词的条件。
在一天结束时,一旦调用未定义的行为,程序的行为就无法预测。这里的理念是,最好是崩溃并让开发人员指出某些事情是严重错误的,并允许他们调试正确的点,而不是生成一个似乎有效但实际上已经破坏的程序。
正如鲁斯兰指出的那样,它是有效的&#34;从某种意义上说,它保证引发无效的操作码异常,而不是将来可能有效的其他未使用的序列。