首页
社区
课程
招聘
关于C语言的自增意料之外的结果
发表于: 2012-10-10 16:56 5770

关于C语言的自增意料之外的结果

2012-10-10 16:56
5770
#include<stdio.h>

void main()
{
	int i=5;
	int y;
	y=(++i)+(++i)+(++i);
	printf("y=%d  i=%d\n",y,i);
}


我能计算出来i的最后结果是8,对于y我的计算结果是6+7+8=21,但是编译器的结果却是22.
[ ATTACH ] 捕获.JPG[ /ATTACH ]

请帮忙解答为什么y的结果是22,求解原理。

[课程]Android-CTF解题方法汇总!

上传的附件:
收藏
免费 0
支持
分享
最新回复 (16)
雪    币: 6508
活跃值: (3122)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
经典问题了
自己看反汇编吧
不要再用这种代码调戏编译器了....
2012-10-10 17:09
0
雪    币: 220
活跃值: (117)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
好神奇! 我怎么想怎么是21啊
2012-10-10 17:10
0
雪    币: 220
活跃值: (117)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
求解..为啥会出现这个问题?..如果是经典问题..帮弄个答案好么亲~
2012-10-10 17:14
0
雪    币: 1021
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zig
5
与编译器的具体实现有关,不同的编译器结果可能不一样的
唉,为啥总是有人在纠结这种问题呢,晦涩难懂难维护的代码。。。。。
2012-10-10 17:30
0
雪    币: 678
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
7:        sum = (++i) + (++i) + (++i);
0040102F   mov         eax,dword ptr [ebp-4]
00401032   add         eax,1
00401035   mov         dword ptr [ebp-4],eax
00401038   mov         ecx,dword ptr [ebp-4]
0040103B   add         ecx,1
0040103E   mov         dword ptr [ebp-4],ecx
00401041   mov         edx,dword ptr [ebp-4]
00401044   add         edx,dword ptr [ebp-4]
00401047   mov         eax,dword ptr [ebp-4]
0040104A   add         eax,1
0040104D   mov         dword ptr [ebp-4],eax
00401050   add         edx,dword ptr [ebp-4]
00401053   mov         dword ptr [ebp-8],edx

00401044   add         edx,dword ptr [ebp-4]
自增到7之后才累加
2012-10-10 17:32
0
雪    币: 6508
活跃值: (3122)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
7
其实很好理解,编译器不如人聪明,它只会按流程和规定走
不同的编译器对这段代码也有不同的理解和优化,算出来的结果也是不同的
这段代码有很多 运算优先级问题,导致编译器不知是先加后再运算还是先运算后再加,具体可以看反汇编
JavaScript算出来就是21,因为它不受编译器的影响
这种问题你可以百度或谷歌嘛,搜索 C 自加,估计楼主是从鱼C那里来的.....
这种代码平常根本用不到,只能拿来作为一个编译器相关的问题来讲,看多了容易晕,用不着计较
2012-10-10 17:41
0
雪    币: 6
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
楼主,这种问题问的人太多了。我认为正确的答案是:不同的编译器,结果不同(本人亲测),所以不要纠结在这个问题上了。
2012-10-10 17:51
0
雪    币: 31
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
我用TC2.0 输出24和8
2012-10-10 17:59
0
雪    币: 36
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
不同的编译器问题,如果有汇编基础看下就知道了
2012-10-10 18:23
0
雪    币: 26
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
[QUOTE=魔之幻灵;1107963]7:        sum = (++i) + (++i) + (++i);
0040102F   mov         eax,dword ptr [ebp-4]
00401032   add         eax,1
00401035   mov         dword ptr [ebp...[/QUOTE]

增加到7?那不就是7+8+9了?也不对啊,编译器显示的结果最后它是8啊
2012-10-10 20:44
0
雪    币: 26
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
谢谢了,但是我还是不知道VC6.0出22的原理啊
2012-10-10 20:46
0
雪    币: 22
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
应该是运算符优先级的问题吧?
  
(++i)+(++i) 是一个运算式,++的优先级高于+,因此算两次++后再算+,
这样就等同于((++i)+(++i))+(++i) = (7+7)+8 = 22。
  
至于javascript的21,它是解释性语言,一边读取一边计算,就是6+7+8=21.
  
TC2.0应该是把算式当成一个整体来做运算,于是三个++ 运算符的优先级高于两个+运算符的优先级,就成了8+8+8=24。
2012-10-10 20:59
0
雪    币: 22
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
补充:VC6.0这种处理方法,应该是源于对运算符重载的编译需求。
  
C语言是不支持运算符重载的,而C++是支持的,因此 TC 2.0和 VC 6.0的编译方式不同,运算结果不同。
2012-10-10 21:04
0
雪    币: 2993
活跃值: (25)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
15
最近刚好在学编译器设计,试着解释一下吧。
首先,这里用到编译器有两个很重要的性质:
i.自左向右读取,步步为营,并且在能完成该语句的情况下尽可能少的读取字符。(比如False&&A无论A的真假都会判定为0)
ii.在满足i的条件下,对于重复的单位进行归并,以减少运算次数。

于是,编译器读取语句(++i)+(++i)+(++i)的顺序如下:
a.括号优先级最高,读取第一个括号,++i,此时i=6
b.继续读一个加号,判断为二元运算符,继续读
c.读取第二个括号,i++,此时i=7
d.编译器发现a和c中用了相同的部分,于是根据【性质ii】使用同一个结果来运算,7+7=14,作为缓存留下
e.读取一个加号,判断为二元运算符,继续读
f.读取第三个括号,i++,此时i=8
(注意,读取到这里时,前面的两个++i已经被运算并把结果放在缓冲里面,所以不再存在++i了,也就不再满足【性质ii】)
g.运算14+8=22
2012-10-10 22:06
0
雪    币: 30
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Tau
16
我也在这个问题上纠结了  很长时间
2012-10-10 22:19
0
雪    币: 144
活跃值: (31)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
无聊至极!!
2012-10-10 22:26
0
游客
登录 | 注册 方可回帖
返回
//