提问者:小点点

编译器是否允许在不同函数参数中交错子表达式的计算?


我想知道以下情况:

void f(int a, int b) { }

int a(int x) { std::cout << "func a" << std::endl; return 1; }
int b(int x) { std::cout << "func b" << std::endl; return 2; }

int x() { std::cout << "func x" << std::endl; return 3; }
int y() { std::cout << "func y" << std::endl; return 4; }

f(a(x()), b(y()));

阅读后http://en.cppreference.com/w/cpp/language/eval_order我仍然难以理解以下评估顺序是否可行:

x()-

或者标准保证a(x())b(y())将被评估为单位,可以这么说。

换句话说,是否有可能打印

func x
func y
func a
func b

在GCC 5.4.0上运行此测试使我的思想更合乎逻辑

func y
func b
func x
func a

但这当然不能告诉我标准要求什么。如果能参考一下这个标准,那就太好了。


共2个答案

匿名用户

在C 14及更早版本中,x-

  • x的调用在调用a之前排序
  • y的调用在调用b之前排序
  • a的调用在调用f之前被排序
  • b的调用在调用f之前排序

订单没有其他限制。如果要强制实施某些特定排序,则必须将此调用分解为多个完整表达式。

在C 14标准中,注释[expr.call]/8阐明了这一意图:

[注意:后缀表达式和参数的计算都是相对于彼此未排序的。参数计算的所有副作用在输入函数之前进行排序。—尾注 ]

正如注释中所指出的,cpreference页面列出了更多标记为“自C 17以来”的排序规则。这是基于最新发布的C 17草案n4606。因此,对于C 17,可能不再允许此订单。

匿名用户

换个角度来看:

在开始评估 a 或 b 之前同时评估 x 和 y 没有任何好处。事实上,会有惩罚。额外的中间结果必须暂时保存在需要额外堆栈推送/弹出或消耗额外 CPU 寄存器(过度使用会导致额外的堆栈操作)的某个地方。虽然对于您提供的示例来说,这可能影响很小或没有影响,但更复杂的案例会揭示效率低下的情况。

该规则可以被视为尽可能懒惰的评估,即直到需要时才进行评估,以避免带来额外的临时结果。