同一段c语言代码为何输出结果不一样?

书上有一段代码,我做了一下,发现在不同的软件上结果不一样,前面两个是在mac上的sublime text上做的,接下来两张分别在xp的vc++和win…
关注者
130
被浏览
59,158
登录后你可以
不限量看优质回答私信答主深度交流精彩内容一键收藏

有时候其实不是很想回答这种问题,因为被问了几十年了。但是鉴于没有什么像样的回答,刚关注c/c++,做点贡献。

c++11后的标准对这类问题定义的很明确,比以前更容易懂。所以直接看标准就好了。

Given any two evaluations A and B, if A is sequenced before B, then the execution of A shall precede the execution of B. If A is not sequenced before B and B is not sequenced before A, then A and B are unsequenced.

首先是定义: 如果语句A在语句B之前执行,那么就叫做A sequenced before B。

如果A不是sequenced before B,同时B不是sequenced before A,那么就叫unsequenced。

可能有人看糊涂了,稍微解释下,

int a = 10;  //A
int b = 10;  //B
int c = a + b; //C

A是sequenced before B,B是sequenced before C。没有什么歧义,不难理解。

其实标准中明确说了:

Every value computation and side effect associated with a full-expression is sequenced before every value computation and side effect associated with the next full-expression to be evaluated.

简单点说,就是每个分号前的语句(full-expression,不算for loop那种的分号),一定sequenced before 分号后的语句。

那么什么情况下,A不sequenced before B,同时B也不sequenced before A,怎么可能呢。

其实也不难理解,就是A可能在B之前执行,B也可能在A之前执行,甚至A和B可以交叉执行。

下面的例子,

int a = 10;
int b = 5;
int c = (a+b) * (a-b);

前面那个(a+b)是A,后面那个(a-b)是B,这是典型的unsequenced例子。为何?为了优化。稍微学学编译器优化就了解了,执行顺序不同,效率完全不一样,特别是有流水线的情况下。还有内存优化,cache等问题。C为了效率,就特意规定了这是个unsqeuenced的情况,编译器可以根据cpu,根据上下文随意优化。

注意,unsequenced本身不是错误!就如上面那个例子是正确的写法。

因为即使是unsequenced,上面的例子无论怎样优化,结果都是一样的。

关于unsequenced,标准说:

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.

大概就是说,绝大多数(except where noted) 运算符/操作符(加号减号乘号等等)的2个或者2个以上的运算子/操作子之间是unsequenced。

表达式的2个或者多个子表达式之间也是unsequenced。

例如

int a = 10;
int b = 5;
int add(int i, int j) { return i+j; }
add(a + b, a - b);

以上的a+b和a-b分别是add(a + b, a - b)这个表达式的子表达式,所以也是unsequenced。


最后的最后:

If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, and they are not potentially concurrent, the behavior is undefined.

就是说,如果2个unsequenced的操作,同时改变了同一个object的值(side effect),那么结果就是undefined behavior。

所以楼主的

y=w++*w++*w++;
z=--x*--x*--x;

都是非常典型的undefined behavior。

还有人问

std::cout << i++ << i++ << std::endl;

很明显是一个表达式的子表达式,unsequenced,所以undefined behavior