foo(bar())等代码中的函数执行顺序是什么?

时间:2017-03-01 20:02:12

标签: c++ c

假设我们在C或C ++中有这样的代码:

foo(bar());

在这种情况下,函数执行顺序是什么?

  1. 是否需要先调用bar(),并且foo()不早于bar()返回,在这种情况下,foo()会传递bar()的返回值1}}?
  2. 是否允许编译器对上述内容进行重新排序,即它首先调用foo(),并延迟调用bar(),直到foo()的代码中foo()的值为foo()实际上需要参数吗?
  3. 案例2可以用于优化void foo(someType par) { if(someTest()) baz1(); else baz2(par); } 如下定义:

    bar()

    如果someTest()返回false,则可以完全跳过调用id name unused time 1 a 1 2/21/2017 18:01:31.168 1 a 2 2/21/2017 18:01:31.168 1 a 3 2/21/2017 18:11:44.054 1 a 4 2/21/2017 18:19:03.147 1 b 5 2/21/2017 18:19:03.147 1 b 6 2/21/2017 21:55:43.927 1 b 7 2/21/2017 22:10:29.699 1 b 8 2/21/2017 22:10:29.699 2 a 9 2/21/2017 23:36:30.239 2 a 10 2/21/2017 23:45:40.005 2 a 11 2/22/2017 00:05:43.466 2 a 12 2/22/2017 00:05:43.466 2 b 13 2/22/2017 00:16:00.646 2 b 14 2/22/2017 11:43:16.250 2 b 15 2/22/2017 11:43:16.250 2 b 16 2/22/2017 14:02:10.531 的情况。

    然而,案例2也会使程序员必须更加小心,因为它有时会导致细微的错误(例如重复发生)。

6 个答案:

答案 0 :(得分:5)

在C ++中,[intro.execution]:

  

当调用函数时(无论函数是否为内联函数),在执行每个表达式或语句之前,对与任何参数表达式或指定被调用函数的后缀表达式相关联的每个值计算和副作用进行排序。被调用函数的主体。

在调用bar()之前,必须先评估

foo

C ++ 17中有一些变化,表达式a(b)现在在a之前评估b,而在它们未被排序之前。在这种情况下,foo的评估不做任何事情,它只是一个标识符。但如果我们有foo()(bar()),那么对foo()的调用将在调用bar()之前进行排序,而在C ++ 17之前,对这两个调用没有排序。

答案 1 :(得分:3)

  
      
  1. 是否需要首先调用bar() [...]?
  2.   

要求代码表现得好像发生了什么。

  
      
  1. 是否允许编译器重新排序上述[...]?
  2.   

是的,如果可观察的行为与首先评估bar()的行为相同。

这称为"as-if" rule

  

[...]只要结果就好像是遵守了要求,只要可以从程序的可观察行为中确定,实施就可以自由地忽视本国际标准的任何要求。

答案 2 :(得分:2)

除了别人所说的,你可以考虑

  foo( bar1(), bar2() );

这是一个更有趣的案例。这里的顺序允许是[bar1,bar2,foo]或[bar2,bar1,foo]。

答案 3 :(得分:0)

在函数参数评估之后有一个序列点(即在输入任何函数的代码之前)。因此,必须在输入bar()之前评估foo(...)。例如,提供C11 standard

  6.5.2.2函数调用:(10)在评估函数指示符和实际参数之后但在实际调用之前有一个序列点。调用函数(包括其他函数调用)中的每个评估(在执行被调用函数体之前或之后没有特别排序)对被调用函数的执行进行不确定的排序。

答案 4 :(得分:0)

如果您有以下声明

foo(bar());

bar()之前调用函数foo()。编译器无法重新排序这些函数调用。

答案 5 :(得分:0)

它与:

相同
type bar_result = bar();
foo(bar_result);
    首先会调用
  1. bar()。
  2. bar_result作为副本/参考文件传递。