转自:
http://www.cnblogs.com/Levins/archive/2004/11/25/68572.html
看见有个面试题目,求x, y的值:
int i = 3, j = 3; int x = (++i) + (++i) + (++i); int y = (j++) + (j++) + (j++);
看到挺多人在争论,这样的表达式值应该是多少?甚至拿出几个不同的编译器来编译运行得到几个不同的结果。对于此题的答案,一句话,The behavior is undefined! 详细解释待我慢慢说来。
大家知道,通常而言,我们写的计算机程序都是从上到下,从左到右依次执行。然而,我只是说通常,因为在编译的过程中,compiler并不仅仅是把source code翻译成binary code就算了,这个过程里面可能还会对代码进行优化,这种优化可能带来的结果是:代码或者表达式evaluation的顺序可能发生变化。这可是一个非常严重的问题,当某个表达式带有side-effect(比如改变了一个变量的值),那么它的执行顺序直接影响到了程序执行的结果。
为了保证程序执行具有确定性的结果,C++标准引入Sequence Point这个概念,按照ISO/IEC的定义:
At certain specified points in the execution sequence called sequence points. All side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place.
简而言之,Sequence Point就是这么一个位置,在它之前所有的side effect已经发生,在它之后的所有side effect仍未开始,而两个Sequence Point之间所有的表达式或者代码执行的顺序是未定义的!
而C++标准又进一步规定了Sequence Point出现的5种情况:
- At the end of a full expression
- After the evaluation of all function arguments in a function call and before execution of any expressions in the function body
- After copying of a returned value and before execution of any expressions outside the function
- After evaluation of the first expression in a&&b, a||b, a?b:c, or a,b
- After the initialization of each base and member in the constructor initialization list
具体我不详细讨论,只看第一个情况:At the end of a full expression,这里简化问题,full expression简单认为是一个带有;的语句(具体可以再去查标准)。也就是说,任何一个独立的表达式语句的结束都是一个Sequence Point,回到我们的题目:
int y = (++i) + (++i) + (++i);
整个的语句里面,只有1个Sequence Point,也就是语句的结束点,对于右边表达式的计算顺序没有任何的规定,显然,各种编译器都可以按照他们觉得“舒服”的方式来进行计算,这样的代码,如果只要求在特定的平台或者编译器运行,那么带来的可能只是可读性差的问题,但如果考虑跨平台或者编译器的情况,那么就是完完全全的错误!
另外,需要特别注意的是,对于赋值号(assignment operator),C++也没有把它定义成Sequence Point,也就说这样的语句:
buffer[i] = i++;
同样是undefined的,因为,对于等号左右两边的表达式运算顺序,你并不能有任何的假定。