C++ 为什么c+中未指定函数参数的求值顺序+;?

C++ 为什么c+中未指定函数参数的求值顺序+;?,c++,operator-precedence,C++,Operator Precedence,该标准没有使用以下行指定参数的求值顺序: 未指定参数的求值顺序 什么是 在没有限制的情况下,可以生成更好的代码 表达式求值顺序 暗示 例如,要求所有编译器从左到右计算函数参数有什么缺点?由于这个未指定的规范,编译器执行什么样的优化?允许编译器对操作数的求值重新排序,增加了更多的优化空间 下面是一个完全虚构的示例,用于说明 假设处理器可以: 每个周期发布1条指令 在1个周期内执行加法 在3个周期内执行乘法运算 可以同时执行加法和乘法 现在假设您有一个函数调用,如下所示: foo(a += 1,

该标准没有使用以下行指定参数的求值顺序:

未指定参数的求值顺序

什么是

在没有限制的情况下,可以生成更好的代码 表达式求值顺序

暗示


例如,要求所有编译器从左到右计算函数参数有什么缺点?由于这个未指定的规范,编译器执行什么样的优化?

允许编译器对操作数的求值重新排序,增加了更多的优化空间

下面是一个完全虚构的示例,用于说明

假设处理器可以:

  • 每个周期发布1条指令
  • 在1个周期内执行加法
  • 在3个周期内执行乘法运算
  • 可以同时执行加法和乘法
现在假设您有一个函数调用,如下所示:

foo(a += 1, b += 2, c += 3, d *= 10);
// assume that p is a pointer to an integer
foo(*p * 3, bar(), *p * 3 + 1);
如果要在处理器上从左到右执行此操作,而无需:

现在,如果允许编译器对它们重新排序:(并首先开始乘法运算)

所以6个周期和4个周期


同样,这完全是人为的。现代处理器比这复杂得多。但是你明白了。这里有一个简单的例子。假设您有一个函数调用,如下所示:

foo(a += 1, b += 2, c += 3, d *= 10);
// assume that p is a pointer to an integer
foo(*p * 3, bar(), *p * 3 + 1);
编译器需要取消引用
p
两次(并根据结果进行一些计算),然后调用
bar
一次。如果编译器很聪明,它可能会将计算重新排序为

int temp = *p * 3;
foo(temp, bar(), temp + 1);

这样,它只需执行一次“解引用,乘以3”。这就是所谓的公共子表达式省略。

允许编译器对操作数的求值进行重新排序,增加了更多的优化空间。@Mysticial:看起来很荒谬,但这应该是一个答案,实际上是公认的答案!编译器执行什么样的优化?如果我能想出一个例子,我将给出答案。一些调用约定从右向左传递参数。其他的从左到右传递。有时,按照推送的顺序进行求值更有效。公平地说,即使是保证求值顺序的语言也可以这样做,前提是它们可以证明
p
的值不能在两者之间变化。当然,对于C内存模型来说,这几乎是不可能保证的,这可能就是为什么不定义求值顺序对于实现这种优化是必要的。