以下给是我从《C语言与程序设计大学教程》一书为大家摘抄出来的内容,这一内容显然能解答大家的问题,我认为可以终止大家对这一问题的讨论:)。
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int x = 3;
int a;
a = ++x + ++x + ++x;
/*等号右侧的表达式有三个副作用发生*/
printf("a = %d", a);
system("PAUSE");
return 0;
}
表达式++x + ++x + ++x有3个副作用:x自增1、x自增1、x自增1。问题的关键是:标准对于副作用的发生顺序未做定义。从而,对实现而言,可以先执行第一个++x,可能先执行第二个++x,也可能先执行第三个++x。标准只规定:一个表达式的全部副作用,不在到达该表达式紧邻的前一序列点前发生,并且一定在到达该表达式紧邻的下一个序列点之前发生完毕。
序列点被定义为程序执行过程中的这样一个点:该点前的表达式的所有副作用,在程序执行到达该点之前发生完毕;该点后的表达式的所有副作用,在程序执行到该点时尚未发生。C语言的大部分表达式都没有序列点,序列点会出现在:
1) 完整表达式结束时。即出现在初始化语句、表达式语句、return语句中的表达式和条件表达式或switch语句中的控制表达式(包括for语句中的每个表达式)之后。
2) &&、||、?:或逗号运算符的第一个操作数之后。
3) 函数调用中求值参数和函数表达式之后。
a = ++x + ++x + ++x; 中,“;”后会被插入一个序列点(简单起见,称“;”就是序列点),因为程序执行到“;”前,表达式 a = ++x + ++x + ++x中的所有副作用都发生完毕,且“;”之后的表达式的所有副作用还未发生。因此,上述3个副作用只需要在遇到“;”之前结束就可。
在VS2005中,从上一个序列点(即int a;语句中的“;”)开始,表达式a = ++x + ++x + ++x的执行顺序为:
1)
执行三个副作用,使x变成6
2)
计算6 + 6,得12
3)
计算12 + 6,得18
4)
将18赋给a
5)
遇到序列点“;”
从而VS2005输出:a = 18。
在Dev C++中,从上一个序列点开始,表达式a = ++x + ++x + ++x的执行顺序为:
1)
先执行两个副作用,使x变成5
2)
计算5 + 5,得10
3)
再执行第三个副作用,使x变成6
4)
计算10 + 6,得16
5)
将16赋给a
6)
遇到序列点“;”
从而Dev C++输出:a = 16。
根据上面的描述,VS2005、Dev C++这两个实现都符合标准。因为,3个副作用都在两个紧邻的序列点间执行完毕。出现不同输出的主要原因就在于:3个副作用发生的顺序在两个不同实现中不一样。
由上可知,由于副作用的发生顺序是未定义的,这就意味着相应表达式的值是不确定的。因此,即使是掌握了副作用、序列点等相关知识,也不建议利用表达式求值的副作用。
实际工作中,完全可以通过引入中间变量,避开副作用造成了岐义。