C#赋值子表达式的求值顺序是否依赖编译器?
关于你写的表达式求值逻辑的严谨性分析
首先明确:你的表达式行为在C++17及以后的标准下是确定的,但在C++17之前属于依赖编译器实现的未指定行为,存在不一致风险。
你的求值过程理解是否正确?
在C++17及以后,你的步骤完全正确:
- 先读取
condition的旧值(步骤1) - 调用
AssignmentFunction()并将结果赋值给condition(步骤2) - 比较旧值和新值是否不等(步骤3)
- 若比较结果为真,再读取更新后的
condition值做&&判断(步骤4),否则跳过这一步(短路特性) - 将步骤4的结果赋值给
conditionWasntTrueButNowIs(步骤5) - 判断该赋值结果是否为真,若为真则整个
||表达式为真,否则再读取更新后的condition值判断(步骤6) - 最后根据步骤6的布尔值得到1或0的结果(步骤7)
但在C++17之前,condition != (condition = AssignmentFunction())这个子表达式的操作数求值顺序是未指定的——编译器可以选择先执行右边的赋值,再读取左边的condition(此时已经是新值),这会导致比较结果永远是false,和你的预期完全不符。
为什么你的分步等价代码更可靠?
你写的分步代码:
bool newVal = AssignmentFunction(); conditionWasntTrueButNowIs = (condition != newVal) && newVal; condition = newVal; int result = condition ? 1 : 0;
完全规避了求值顺序的问题:先把AssignmentFunction()的结果存到临时变量,再用旧的condition和临时变量比较,最后更新condition。这个逻辑在所有C++标准下都是确定的,不会受编译器实现影响。
总结
- 如果你的代码只需要兼容C++17及以后,原表达式的行为和你的理解一致,是严谨的;
- 如果需要兼容更早的C++标准,原表达式存在行为不确定的风险,推荐用你的分步代码替代。
内容的提问来源于stack exchange,提问作者Dagan Hartmann
相关产品推荐
相关产品推荐

