为什么在c ++中未指定函数参数的评估顺序?

unj*_*nj2 11 c++ operator-precedence

该标准未指定使用此行评估参数的顺序:

参数的评估顺序未指定.

是什么

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

意味着?

例如,要求所有编译器评估函数参数Left to Right有什么缺点?由于这个未指定的规范,编译器执行了哪些优化?

Mys*_*ial 27

允许编译器重新排序操作数的评估,为优化增加了更多空间.

这是一个完整的例子,用于说明目的.

假设处理器可以:

  • 每个周期发出1条指令.
  • 在1个循环中执行添加.
  • 在3个周期内执行乘法运算.
  • 可以同时执行加法和乘法.

现在假设您有一个函数调用,如下所示:

foo(a += 1, b += 2, c += 3, d *= 10);
Run Code Online (Sandbox Code Playgroud)

如果你在没有OOE的处理器上从左到右执行:

Cycle - Operation
0     -    a += 1
1     -    b += 2
2     -    c += 3
3     -    d *= 10
4     -    d *= 10
5     -    d *= 10
Run Code Online (Sandbox Code Playgroud)

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

Cycle - Operation
0     -    d *= 10
1     -    a += 1, d *= 10
2     -    b += 2, d *= 10
3     -    c += 3
Run Code Online (Sandbox Code Playgroud)

所以6个周期对4个周期.

这完全是人为的.现代处理器要复杂得多.但是你明白了.


Ray*_*hen 5

这是一个简单的例子。假设您有一个函数调用如下:

// assume that p is a pointer to an integer
foo(*p * 3, bar(), *p * 3 + 1);
Run Code Online (Sandbox Code Playgroud)

编译器需要取消引用p两次(并根据结果进行一些计算)并调用bar一次。如果编译器很聪明,它可能会将计算重新排序为

int temp = *p * 3;
foo(temp, bar(), temp + 1);
Run Code Online (Sandbox Code Playgroud)

这样它只需执行一次“取消引用,乘以 3”。这称为公共子表达式消除。

  • 公平地说,即使是保证求值顺序的语言也可以做到这一点,只要它们可以证明“p”的值在两者之间不会改变。当然,对于 C 内存模型来说,这几乎是不可能保证的,这可能就是为什么需要未定义的评估顺序来实现这种优化。 (3认同)