具有未定义结果的C代码,编译器生成无效代码(使用-O3)

时间:2014-10-10 23:10:39

标签: c gcc undefined-behavior

我知道当你在C程序中做某些事情时,结果是不确定的。但是,编译器不应该生成无效(机器)代码,对吧?如果代码做错了,或者代码生成了段错误或其他东西,那将是合理的......

这应该根据编译器规范发生,还是编译器中的错误?

这是我使用的(简单)程序:

int main() {
    char *ptr = 0;
    *(ptr) = 0;
}

我正在使用-O3进行编译。那不应该生成无效的硬件指令,对吗?使用-O0,我在运行代码时遇到段错误。这看起来更加明智。

编辑:它生成ud2指令......

1 个答案:

答案 0 :(得分:12)

ud2指令是&#34;有效指令&#34; ,它代表未定义指令并生成无效操作码< / em>异常clang,显然gcc可以在程序调用未定义的行为时生成此代码。

从上面clang链接的理由解释如下:

  

存储为null并通过空指针调用转换为   __builtin_trap()调用(变为陷阱指令,如&#34; ud2&#34;在x86上)。这些在优化的代码中始终发生(如   其他转换的结果,如内联和常量   我们过去只删除包含它们的块   因为他们显然无法到达&#34;。

     

虽然(从迂腐的语言律师的角度来看)这是严格的   是的,我们很快就知道人们偶尔会取消引用null   指针,并且代码执行只是落在了顶部   下一个功能使得理解问题非常困难。从   性能角度,暴露这些的最重要的方面是   压缩下游代码。因此,clang将这些变成了一个   运行时陷阱:如果其中一个实际上是动态到达的,那么   程序立即停止并可以调试。做的缺点   这就是我们通过这些操作来略微膨胀代码   具有控制其谓词的条件。

在一天结束时,一旦调用未定义的行为,程序的行为就无法预测。这里的理念是,最好是崩溃并让开发人员指出某些事情是严重错误的,并允许他们调试正确的点,而不是生成一个似乎有效但实际上已经破坏的程序。

正如鲁斯兰指出的那样,它是有效的&#34;从某种意义上说,它保证引发无效的操作码异常,而不是将来可能有效的其他未使用的序列。