c++ 表达式执行顺序

来源:互联网 发布:2015年人口老龄化数据 编辑:程序博客网 时间:2024/06/02 01:59

计算顺序

在c++中,任何表达式(函数参数,子表达式)中的运算元的计算顺序都是不固定的。对于相同的表达式,编译器可能生成不同计算顺序的指令。

同时,在c++中,没有像从左到右,或从右到左的计算规则(刚接触c++的人,容易将计算顺序与运算符的结合性混淆)。比如表达式:

f1()+f2()+f3()

按加法从左向右的结合性,可以转换为:

(f1() + f2()) + f3()

结合性仅仅提供了,表达式需要计算那些单元,至于这些单元的计算顺序,需要使用其他规则。在本表达式中,f3() ,f2(),f1()的计算顺序是不定的,可能f3()最先计算,也可能,最后计算f3(),或者,先计算f2(),再计算f3()。

计算顺序模型

对于一个表达式,根据运算符的优先级与结合性,生成需要计算的计算单元集合。每两个计算单元有一种顺序关系,根据这种顺序关系,以计算单元为顶点,计算先后关系为边,生成一个有向图。

建立这个有向图之后,进行拓扑排序,即可得到一种执行顺序(因为有向图的拓扑排序不一定唯一,所以,可能产生多种执行顺序;如果这多种执行顺序影响程序的执行结果,则会造成程序行为undefined)

以f1()+f2()+f3()为例,

  1. 生成计算单元集合:{f1(), f2(), f3(),f1() + f2(), (f1() + f2()) + f3()}

  2. 根据规则,生成有向图:(***********)

  3. 有向图拓扑排序
  4. 生成执行顺序

Sequenced-before rules

任何一个表达式或子表达式的计算,可能包含两个计算单元(0,1,2):

  • 值计算:
    计算表达式返回的值。需要读取对象的值
  • side effect:
    修改对象,调用IO函数

两个计算单元的计算顺序关系包含以下四种:

  1. A before B, B必须在A执行完之后执行
  2. B before A, A必须在B执行完之后执行
  3. A B unsequenced, A和B可以任意顺序执行,内部指令也可以混杂执行
  4. A and B are indeterminably-sequenced, A先于B 或 B先于A

部分sequenced-before rules:

  1. 每一个完整表达式一定先于下一条完整表达式
  2. 一个表达式的值计算(not side effect)一定先于,这个表达是值计算结果的值计算
  3. 函数调用,参数表达式执行早于函数体中的表达式执行
  4. .........

Undefined behavior

  • 对同一个对象有side effect 的两个计算单元,顺序不确定:

     i = ++i + i++; // undefined behavior i = i++ + 1; // undefined behavior (but i = ++i + 1; is well-defined) f(++i, ++i); // undefined behavior f(i = -1, i = -1); // undefined behavior
  • 对同一个对象的,一个side effect 单元与一个值计算单元,顺序不确定:

      cout << i << i++; // undefined behavior  a[i] = i++; // undefined behavior
0 0