【问题标题】:Why is the order of evaluation for function parameters unspecified in c++?为什么在 c++ 中未指定函数参数的评估顺序?
【发布时间】:2012-09-22 03:25:12
【问题描述】:

标准没有用这一行指定参数的评估顺序:

参数的评估顺序未指定。

做什么

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

暗示?

例如,要求所有编译器从左到右评估函数参数有什么缺点?由于这个未指定的规范,编译器会执行哪些类型的优化?

【问题讨论】:

  • 允许编译器重新排序操作数的求值增加了更多优化空间。
  • @Mysticial:看起来很荒谬,这应该是一个答案,实际上是接受的答案!
  • 编译器执行了哪些优化?
  • 如果我能想到一个例子,我会给出答案。
  • 一些调用约定从右到左传递参数。其他人从左到右传递。有时按照推送的相同顺序进行评估会更有效。

标签: c++ operator-precedence


【解决方案1】:

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

这是一个完全虚构的示例,用于说明目的。

假设处理器可以:

  • 每个周期发出 1 条指令。
  • 在 1 个周期内执行加法。
  • 在 3 个周期内执行一次乘法。
  • 可以同时执行加法和乘法。

现在假设你有一个函数调用如下:

foo(a += 1, b += 2, c += 3, d *= 10);

如果您要在没有OOE 的处理器上从左到右执行此操作:

Cycle - Operation
0     -    a += 1
1     -    b += 2
2     -    c += 3
3     -    d *= 10
4     -    d *= 10
5     -    d *= 10

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

Cycle - Operation
0     -    d *= 10
1     -    a += 1, d *= 10
2     -    b += 2, d *= 10
3     -    c += 3

所以 6 个周期与 4 个周期。

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

【讨论】:

    【解决方案2】:

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

    // 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”。这称为公共子表达式消除。

    【讨论】:

    • 公平地说,即使是保证评估顺序的语言也可以做到这一点,只要它们可以证明p 的值不能在两者之间改变。当然,对于几乎不可能保证的 C 内存模型,这可能就是为什么需要未定义的评估顺序来实现这种优化。
    猜你喜欢
    • 2020-06-07
    • 1970-01-01
    • 2018-11-05
    • 1970-01-01
    • 2012-09-14
    • 1970-01-01
    • 1970-01-01
    • 2015-10-15
    相关资源
    最近更新 更多