立即注册
查看: 5288|回复: 3

[原创] 前++和后++引发的血案~~!!

已绑定手机
已实名认证
发表于 2016-5-14 09:46:55 | 显示全部楼层 |阅读模式 来自 广东省东莞市
本帖最后由 宋桓公 于 2016-5-14 09:51 编辑

先看一段奇葩代码:int main(void)
{
        int x = 4;
        int y;
        y = (x++);
        printf("hello world. y = %d.\n", y);
        x = 4;
        y = (x++)+(x++);
        printf("hello world. y = %d.\n", y);
        
        x = 4;
        y = (x++)+(x++)+(x++);
        printf("hello world. y = %d.\n", y);
        x = 4;
        y = (x++)+(x++)+(x++)+(x++);
        printf("hello world. y = %d.\n", y);
        
        x = 4;
        y = (++x);
        printf("hello world. y = %d.\n", y);
        x = 4;
        y = (++x)+(++x);
        printf("hello world. y = %d.\n", y);

        x = 4;
        y = (++x)+(++x)+(++x);
        printf("hello world. y = %d.\n", y);
        return 0;         
        x = 4;
        y = (++x)+(++x)+(++x)+(++x);
        printf("hello world. y = %d.\n", y);
        return 0;
}


而在VS2012(windows运行环境)的测试结果为:
\\后++
y = 4.
y = 8.   //4+4
y = 12. //4+4+4
y = 16. //4+4+4+4
\\前++
y = 5.   
y = 12. //6+6
y = 21. //7+7+7
y = 32. //8+8+8+8


在Ubuntu上测试的结果为:
//后++
y = 4.
y = 9.   //4+5
y =15.  //4+5+6
y = 22. //4+5+6+7
//前++
y = 5.
y = 12. //6+6

y = 19. //6+6+7
y = 27. //6+6+7+8



对应windows上的测试结果都比较好理解:
1、对于后++而言,在赋值之前x不会递增,所以每次多一个x++不过是多一个4的累加而已。
2、对于前++而言,在赋值前x已经递增,所以每次多一个x所对应内存的值都被提高1,最后再相加。
所以出现了出现了6*2  7*3  8*4的结果。

对于linux上的测试结果就不太容易想明白:
1、对于后++而言第二就和windows的结果不一样了,这是因为linux用了产生中间变量的方式。
如:y = (x++)+(x++);被分成了多步:1)tmp = x;  x = x + 1;2) tmp1 = x;  x = x + 1;  3)y  = tmp + tmp1;
1)中tem等于4,并递增了x;2)中tmp1就等4了也递增了x;3)中就等到结果4+5=9
当(x++)递增到三个时也是一样分析,只不过会多一个中间变量tmp2.


2、对于前++,第三个和windows的结果不同了,也是产生了中间变量的缘故:
如:y = (++x)+(++x)+(++x); 被分成了多步:
1)tmp  = (++x)+(++x);  2)y = tmp  +  (++x);
从而y = 6+6+7
再如:y = (++x)+(++x)+(++x); 被分成了多步:
1)tmp  = (++x)+(++x);  2)tmp1 = tmp  +  (++x);  3)y =  tmp1 +  (++x);
从而y = 6+6+7+8



这里可能唯一让人困惑的是为什么(++x)+(++x)中间没有产生中间变量?而(x++)+(x++)却产生了中间变量?
我猜想是因为前++应为是先递增后赋值,所以直接是x = x+1所以也就没有中间变量的产生,而作为最前面的
两个(++x)与‘+’作用产生一个表达式:(++x)+(++x),这个表达式赋值给一个中间变量在与后面的表达式依次作用。




总结:
   1、对于vs的编译器,在一条语句中,没有产生多余的中间变量,而ubuntu中因为产生了中间的变量。
所以后++时ubuntu对x的内存空间有更多的操作,而前++时vs对x的内存空间有更多的操作。导致了结果的不一致。
   2、得知了第一点之后,我们应该注意在一条语句中,不要对一个变量进行多次的操作,因为你不知道编译器,对
对这条语句产生多少个中介变量,而引发血案~~













已绑定手机
已实名认证
发表于 2016-5-14 15:33:32 | 显示全部楼层 来自 广东省深圳市
很好的分享,很多人都不会注意这些细节
已绑定手机
已实名认证
发表于 2016-5-18 10:18:45 | 显示全部楼层 来自 广东省深圳市
顶一个  谢谢楼主
发表于 2016-6-14 00:36:32 | 显示全部楼层 来自 台湾省台南市
本帖最后由 RupertLi 于 2016-6-14 00:39 编辑

这种写法在 C 语言是归为未定义行为,不建议这麽使用。你若打开编译器错误警告,一定会有提示。譬如:

$ LANG=C gcc -Wall a.c
a.c: In function 'main':
a.c:10:15: warning: operation on 'x' may be undefined [-Wsequence-point]
         y = (x++)+(x++);
         ...

请参考: https://zh.wikipedia.org/wiki/未定义行为

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

合作/建议

TEL: 19168984579

工作时间:
周一到周五 9:00-11:30 13:30-19:30
  • 扫一扫关注公众号
  • 扫一扫打开小程序
Copyright © 2013-2024 一牛网 版权所有 All Rights Reserved. 帮助中心|隐私声明|联系我们|手机版|粤ICP备13053961号|营业执照|EDI证
在本版发帖搜索
扫一扫添加微信客服
QQ客服返回顶部
快速回复 返回顶部 返回列表