前++和后++引发的血案~~!!

先看一段奇葩代码:

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);

 

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、得知了第一点之后,我们应该注意在一条语句中,不要对一个变量进行多次的操作,因为你不知道编译器,对这条语句将产生多少个中间变量,而引发血案~~

时间: 2024-08-04 12:05:36

前++和后++引发的血案~~!!的相关文章

一个无锁消息队列引发的血案:怎样做一个真正的程序员?(二)——月:自旋锁

前续 一个无锁消息队列引发的血案:怎样做一个真正的程序员?(一)——地:起因 一个无锁消息队列引发的血案:怎样做一个真正的程序员?(二)——月:自旋锁 平行时空 在复制好上面那一行我就先停下来了,算是先占了个位置,虽然我知道大概要怎么写,不过感觉还是很乱. 我突然想到,既然那么纠结,那么混乱,那么不知所措,我们不如换个视角.记得高中时看过的为数不多的长篇小说<穆斯林的葬礼>,作者是:霍达(女),故事描写了两个发生在不同时代.有着不同的内容却又交错扭结的爱情悲剧,一个是“玉”的故事,一个是“月”

一个Sqrt函数引发的血案

我们平时经常会有一些数据运算的操作,需要调用sqrt,exp,abs等函数,那么时候你有没有想过:这个些函数系统是如何实现的?就拿最常用的sqrt函数来说吧,系统怎么来实现这个经常调用的函数呢? 虽然有可能你平时没有想过这个问题,不过正所谓是"临阵磨枪,不快也光",你"眉头一皱,计上心来",这个不是太简单了嘛,用二分的方法,在一个区间中,每次拿中间数的平方来试验,如果大了,就再试左区间的中间数:如果小了,就再拿右区间的中间数来试.比如求sqrt(16)的结果,你先试

一次优化引发的血案

前些天一个Nginx+PHP项目上线后遭遇了性能问题,于是打算练练手,因为代码并不是我亲自写的,所以决定从系统层面入手看看能否做一些粗线条的优化. 首先,我发现服务的Backlog设置过小,可以通过ss命令查询Send-Q来确认: shell> ss -ln Recv-Q Send-Q Local Address:Port Peer Address:Port 0 511 *:80 *:* 0 128 127.0.0.1:9000 *:* 明显看出,Nginx的Backlog是511:PHP的Ba

【转载】一个Sqrt函数引发的血案

转自:http://www.cnblogs.com/pkuoliver/archive/2010/10/06/sotry-about-sqrt.html 源码下载地址:http://diducoder.com/sotry-about-sqrt.html 好吧,我承认我标题党了,不过既然你来了,就认真看下去吧,保证你有收获. 我们平时经常会有一些数据运算的操作,需要调用sqrt,exp,abs等函数,那么时候你有没有想过:这个些函数系统是如何实现的?就拿最常用的sqrt函数来说吧,系统怎么来实现这

JVM--JVM finalize实现原理与由此引发的血案

原创内容,转载请注明出处 本文由一桩因为使用了JAVA finalize()而引发的血案入手,讲解了JVM中finalize()的实现原理和它的陷阱所在,希望能够对广大JAVA开发者起到一点警示作用.除此之外,本文从实际问题出发,描述了解决问题的过程和方法.如写模拟程序来重现问题,使用jmap工具进行分析等,希望对大家提供借鉴. 本文分三个章节,先介绍实际项目中遇到的问题,随后介绍了问题重现和分析方法,最后对问题的元凶,override finalize()的实现原理和陷阱进行了讲解和介绍.篇幅

ASP.NET Button控件的UseSubmitBehavior属性引发的血案

这里先不说标题上的UseSubmitBehavior属性是什么,先说下面这种情况. 通常,在我们写一个表单页面的时候,最下方会有"提交"和"返回"字样的两个按钮.顾名思义,它们的功能大家都知道,但是一般情况下我们会给表单的内容加上一些验证,这样就出现了一个问题.因为两个按钮是服务器控件(有runat="Server"属性),所以点击按钮之后会先进行验证(无论这里你用的是前台的jQuery.validate验证或者是ASP.NET自带的后台验证控件

ThreadPool.QueueUserWorkItem引发的血案,线程池异步非正确姿势导致程序闪退的问题

ThreadPool是.net System.Threading命名空间下的线程池对象.使用QueueUserWorkItem实现对异步委托的先进先出有序的回调.如果在回调的方法里面发生异常则应用程序会出现闪退.当然是指不处理那个异常的情况下.这不公司的CMS在生产环境频频出现闪退的情况.该死的是,原来用老机器配置不高的情况下没有出现过.换了更好的新机器后出现的. // // 摘要: // 将方法排入队列以便执行,并指定包含该方法所用数据的对象.此方法在有线程池线程变得可用时执行. // //

一个无锁消息队列引发的血案(六)——RingQueue(中) 休眠的艺术 [续]

目录 (一)起因 (二)混合自旋锁 (三)q3.h 与 RingBuffer (四)RingQueue(上) 自旋锁 (五)RingQueue(中) 休眠的艺术 (六)RingQueue(中) 休眠的艺术 [续] 开篇 这是第五篇的后续,这部分的内容同时会更新和添加在 第五篇:RingQueue(中) 休眠的艺术 一文的末尾. 归纳 紧接上一篇的末尾,我们把 Windows 和 Linux 下的休眠策略归纳总结一下,如下图: 我们可以看到,Linux 下的 sched_yield() 虽然包括了

openstack运维实战系列(十三)之glance更改路径引发的&quot;血案&quot;

1. 背景说明 glance在openstack中负责镜像相关的服务,支持将运行的虚拟机转换为快照,镜像和快照都存储在glance中,glance的后端支持多种存储方式,包括本地的文件系统,http,glusterfs,ceph,swift等等. 默认情况下,glance采用本地文件系统的方式存储image,存储的路径为/var/lib/glance/images,随着时间的推移,当镜像越来越多的时候,根目录的空间将会越来越大,所以对于glance的路径来说,需要提前做好规划和准备,如划分一个单