编译器可以跳过对逗号运算符左操作数的评估吗?

Posted

技术标签:

【中文标题】编译器可以跳过对逗号运算符左操作数的评估吗?【英文标题】:Can compiler skip evaluation of comma operator's left operand? 【发布时间】:2013-02-21 06:10:16 【问题描述】:

编译器优化有时会跳过对某些没有结果的语句的评估。但是,这也适用于逗号运算符吗?

以下代码在ideone 上运行没有任何错误,但我预计它会崩溃。

#include <iostream>

int main() 
    int x = (1/0, 2);
    std::cout << x << std::endl;

如果我将语句更改为int x = 1/0;,程序确实会崩溃

【问题讨论】:

未定义 行为与保证崩溃不同。 很公平,但是如果左操作数不是UB怎么办?编译器可以跳过吗? 我相信正如 Alok 在答案中所解释的那样,即这取决于是否发生任何可观察到的事情。这是真的not only for the comma operator。 (顺便说一句,尽管我发表了评论,但我认为这是一个很好的问题,我对问题和答案都 +1 了。) 【参考方案1】:

编译器优化使用 As-if rule

假设规则

允许任何和所有不改变程序可观察行为的代码转换

所以是的,编译器可以对此进行优化。检查以下modified sample

#include <iostream>

int main() 

    int y = 1;
    int x = (y=1/0, 2);
    std::cout << x << std::endl;
    //std::cout << y << std::endl;
 

注释最后一行可以正确编译并执行此代码,而取消注释它会给您带来预期的未定义行为。

正如@jogojapan 正确指出的那样, 重要的是要注意,标准不保证编译器优化,除以零是未定义的行为。所以这段代码确实有一个未定义的行为。可观察到的行为是因为编译器优化了除以零还是由于我们永远无法知道的未定义行为。从技术上讲,这都是未定义的行为。

【讨论】:

我认为这并不容易。什么是“可观察行为”?如果它评估1/0,那么您将“观察”一个不同的行为。意味着,程序的行为会根据优化决策而有所不同。 @AlokSave:子表达式不是从来不用,还得考虑表达式的副作用。这显然具有可观察到的副作用。我只能假设除以零是未定义的行为,因此编译器可以假设(在这种情况下不正确)没有有效的副作用,并且 then as-如果规则可以适用。 (对局部变量的赋值不算作副作用。) 讨论未定义的行为是否可观察是徒劳的......顺便说一句,之前已经讨论过类似的问题:***.com/questions/3863656/… @Nawaz:这里的关键是编译器必须保留所有已定义行为。 1/0 的行为是(明确地)未定义,因此编译器可能会也可能不会触发异常。 @MooingDuck: int main() int a=1/0; 仍然是未定义的行为。因此,对于讨论的情况,编译器是否可以或可能优化它是可以的,但讨论本身并不好,因为从技术上讲,它都是 UB。

以上是关于编译器可以跳过对逗号运算符左操作数的评估吗?的主要内容,如果未能解决你的问题,请参考以下文章

js中的逗号运算符

c语言 逗号表达式

第18课 三目运算符和逗号表达式

C语言逗号表达式

编译器如何知道函数调用中的逗号不是逗号运算符?

x, = ... - 这个尾随逗号是逗号运算符吗?