ere*_*eOn 6 c c++ compiler-construction optimization semantics
今天我与我的一位同事讨论了一个事实,即当启用了激进的优化时,编译器可以改变程序的语义.
我的同事声明,当启用优化时,编译器可能会更改某些指令的顺序.以便:
function foo(int a, int b)
{
if (a > 5)
{
if (b < 6)
{
// Do something
}
}
}
Run Code Online (Sandbox Code Playgroud)
可能会改为:
function foo(int a, int b)
{
if (b < 6)
{
if (a > 5)
{
// Do something
}
}
}
Run Code Online (Sandbox Code Playgroud)
当然,在这种情况下,它不会改变程序的一般行为,并不是很重要.
根据我的理解,我相信这两个if (condition)
属于两个不同的序列点,并且编译器不能改变它们的顺序,即使改变它将保持相同的一般行为.
那么,亲爱的SO用户,关于这一点的真相是什么?
Jam*_*lis 12
如果编译器可以验证这两者之间没有可观察到的差异,那么可以自由地进行这样的优化.
序列点是一个概念性的东西:编译器生成代码,这样它的行为好像都喜欢序列点语义规则随访.如果不遵循这些规则,生成的代码实际上不必遵循这些规则就不会在程序的行为中产生可观察到的差异.
即使你有:
if (a > 5 && b < 6)
Run Code Online (Sandbox Code Playgroud)
编译器可以自由地重新安排它
if (b < 6 && a > 5)
Run Code Online (Sandbox Code Playgroud)
因为两者之间没有可观察到的差异(在这种特定情况下,其中a
和b
是两个int
值).[这个假定它是安全的同时读取a
和b
; 如果读取其中一个可能会导致一些错误(例如,一个有陷阱值),那么编译器将在它可以进行的优化方面受到更多限制.
CB *_*ley 11
由于两个程序片段之间没有可观察到的差异 - 假设实现是一个不使用陷阱值或其他任何可能导致内部比较的东西,而不仅仅是评估true
或者false
- 编译器可以优化一个到其他根据"好像"规则.如果存在一些可观察到的差异或某种方式使得符合程序的行为可能不同,那么如果编译器将一种形式更改为另一种形式,则编译器将是不符合的.
对于C++,请参见1.9 [intro.execution]/5.
执行格式良好的程序的一致实现应该产生与具有相同程序和相同输入的抽象机的相应实例的可能执行序列之一相同的可观察行为.但是,如果任何此类执行序列包含未定义的操作,则此国际标准不要求使用该输入执行该程序的实现(甚至不考虑第一个未定义操作之前的操作).
[这项规定有时被称为"假设"规则,因为只要结果好像符合要求,实施可以自由地忽视本国际标准的任何要求,只要可以从可观察的数据中确定该计划的行为.例如,实际实现不需要评估表达式的一部分,如果它可以推断出它的值没有被使用,并且没有产生影响程序的可观察行为的副作用.