这段简单的程序的输出我怎么都不明白,为什么是1 9 25而不是2 12 30呢?

#include<stdio.h>
#define SQ(y)((y)*(y))
void main()
{
int i=1;
while(i<=5)
printf("%d\n",SQ(i++));
}为什么结果是1 9 25 呢?

推荐  (0) | 5人关注关注
3个答案
12 0

傅里叶变黄油猫软件工程师,应用数学专业

2013-04-17 23:28

噢卖糕~~~恭喜哥你踩了一个“未定义行为”的陷阱~~~~

《C++ Standard》1.9.16:

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [Note: In an expression that is evaluated more than once during the execution of a program, unsequenced and indeterminately sequenced evaluations of its subexpressions need not be performed consistently in different evaluations. — end note ] The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. 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, the behavior is undefined.

简单说,如果你在同一句代码中(两个分号之间的代码)执行两次对同一变量的修改,并且两次修改的表达式"unsequenced"(意思是“无序”。除了非函数调用那个“,”,其余操作符的左右表达式都是无序的,包括本例中的“*”。),或者虽然有序但一次依赖于另外一次的“副作用”,那是“未定义行为”。

“未定义行为”是任何程序最糟糕的写法,因为这意味着完全不可预料的执行效果,可能有你想要的结果,可能会爆错,可能会破坏数据,什么都有可能~ 当你做了未定义行为,发生任何事情都不能责怪编译器,都是你的错哦!

后缀++运算符对变量的修改保证在下一句代码或进入函数前完成,但只要符合这个规定,实际在什么时候完成是未知的!例如:
i=i++;
++的累加作用,在等号赋值前还是赋值后发生呢?不知道!C++标准明确说这是“未定义行为”。又例如:
f(i++);
那进入函数体时,i递增了没有?这个看起来和i=i++没本质区别,但这是例外,递增保证发生在 f() 内代码执行前。

C++标准该段英文后面还有例子,也供参考:

[Example:
void f(int, int);
void g(int i, int *v) {
i = v[i++]; // the behavior is undefined
i = 7, i++, i++; // i becomes 9
i = i++ + 1; // the behavior is undefined
i = i + 1; // the value of i is incremented
f(i = -1, i = -1); // the behavior is undefined
}
— end example ]

实际的实验结果,不同的编译器会跑出不同的结果,VC跑得1 9 25,别的编译器可能是2 12 30,聪明的编译器会给你一个警告(一定会被你忽略的是吧?)。

那实际编译器是如何处理未定义行为的呢?——它们基本上不处理!也就是说,编译器的设计是假设你永远不会做未定义行为。这听起来很不负责任,但在C/C++中允许未定义行为,让开发者自行避免并不是不负责,而是一种权衡:虽然很难学很容易出错,但可以有效提高代码的效率——效率是C和C++的核心优势和强项。最典型的例子是C语言编译出的代码从来不会进行数组越界检查,C++的STL也是,越界访问通通是未定义行为。

1 1
支持者: 章鱼喵.时见疏星

运行到SQ(i++)时具体就应该是运算这样一个式子: (i++)*(i++), 这时因为“++”是后置的所以优先级在“*” 之后,所以先计算(i)*(i++) 后面同理,所以先计算 i*i,初始值是1, 所以第一个结果是1, 而不是2 ,接下来计算两个“++”, i值变为3,所以下一个输出9,以此类推

0 0

这类问题是一个陷阱:没有意义且结果未定。它的结果会因编译器实现不同而不同。

作为一个C程序猿,必须得懂i++,++i的区别。至于类似题目这样的宏嵌套自增运算符,正常商业程序都不会这么写。

我手下员工要是敢这么写,就给他两个选择:要么改掉要么滚蛋。

查看更多

添加回答

登录 后回答问题,你也可以用以下帐号直接登录

相关问答

关于我们 加入果壳 媒体报道 帮助中心 果壳活动 家长监控 免责声明 联系我们 移动版 移动应用

©果壳网    京ICP证100430号    京网文[2018] 6282-492号    新出发京零字东150005号     京公网安备11010502007133号

违法和不良信息举报邮箱:jubao@guokr.com    举报电话:18612934101    网上有害信息举报专区    儿童色情信息举报专区