i++,++i, i=i+1 vs编译器上的深入研究

转载 2012年03月29日 20:09:58

今天看到一个有趣的输出,遂发现这篇文章:http://www.cnblogs.com/confide/archive/2012/03/08/2385739.html

我自己的例子是

int i = 10;
  cout << i++<<" " << --i<<" " << ++i<<" " << i--<<endl;

目测输出时 10 10 11 11;实际输出了 9 10 10 10 。使用flush发现也不是缓冲区的问题

i++,++i, i=i+1 vs编译器上的深入研究

首先三者都是等价的操作,三者的效率也都是等价的,这是vs2010的反汇编,三者都被转成相同的汇编代码:

01041375 mov eax,dword ptr [i]
01041378 add eax,1
0104137B mov dword ptr [i],eax
三者在表达式中需要注意的:
i++ = 1; (错误,语法提示i++不能作为左值)
++i = 1; (正确)
如下程序:
int i = 0;
++i = 0;
结果i为0,说明++i=0;表达式的解释为:
++i=0; ------> i=i+1;
i=0;
对于输出的奇怪现象:
int i = 0;
cout<<i++<<" "<<i++<<endl;
cout<<i<<endl;
//1 0
//2
 
i=0;
cout<<i++<<" "<<++i<<endl;
cout<<i<<endl;
//1 2
//2
 
i=0;
cout<<++i<<" "<<++i<<endl;
cout<<i<<endl;
//2 2
//2
 
i=0;
cout<<++i<<" "<<i++<<endl;
cout<<i<<endl;
//2 0
//2
 
 
cout<<i++<<endl;        
编译器在i++的基本汇编代码中插入了一句,即先将取出来的i的值存入临时变量中,然后在打印的时候从临时变量中取出压进输出栈
cout<<++i<<endl;    
编译器并没有在++i的基本汇编中插入任何东西,而是在要打印的时候直接从变量i中取出压进输出栈。
 
知道这两点不同就可以很好的理解上述的奇怪现象。
还是需要记住两点的是:
1、在整个输出语句中,都是先对所有的表达式求值后(保存相应的输出信息)再执行输出操作。
2、cout<<i 这种样式的输出只是调用operator <<成员函数的简单形式,
 
cout<<i++<<" "<<i++<<endl;
首先计算第二个i++表达式,再计算第一个,保存信息到临时变量中,即dword ptr [ebp-0D0h]dword ptr [ebp-0D4h]中,完成后,先将第二个其值从临时变量中取出压入输出栈,再操作第一个。
 
cout<<i++<<" "<<++i<<endl
这个就是我们不明白其操作原理的最奇怪的例子了,和之前解释的一样,将++i的输出信息压栈的时候是直接从变量i中取出来的值,所以是2(表达式全都计算完的结果),而i++则是保存的临时值(计算i++表达式时保存的临时值)。
知道了这些,下面的两个例子就很好解释了。
cout<<++i<<" "<<++i<<endl;
//2 2
i=0;
cout<<++i<<" "<<i++<<endl;
//2 0
但是为什么会这样?还是不从得知。。。。。。。。。。。。。

深入研究socket编程(5)——I/O复用的高级应用

高级应用一:非阻塞connect connect系统调用的man手册中有如下的一段内容: [cpp] view plaincopyprint? EINPROGRESS ...

深入研究socket编程(2)——I/O多路转接(select、pselect和poll)

I/O多路转接:先构造一张有关描述符的列表,然后调用一个函数,直到这些描述符中的一个已准备好进行I/O时,该函数才返回。在返回时,它告诉进程哪些描述符已准备好可以进行I/O。      poll、p...

深入研究socket编程(6)——高级I/O复用(select、poll 、 epoll)

问题聚焦:     前篇提到了I/O处理单元的四种I/O模型。     本篇详细介绍实现这些I/O模型所用到的相关技术。     核心思想:I/O复用 使用情景: 客户端程序要同时处理多个...

c语言的菜鸟理解到深入学习1--关于printf的小细节printf(s,i);竟然是对的

#include  int main() { char* s = "%d"; int  i =7; printf(s,i); return 0; }

GCC编译器中的-I -L -l 选项

在本文中, 我们来聊聊gcc中三个常见的参数, 也即-I(大写的i), -L(大写的l)和-l(小写的l)          一. 先说 -I   (注意是大写的i)         我们先来...

i.MX6 安装交叉编译器

步骤 1 :将文件 gcc-4.6.2-glibc-2.13-linaro-multilib-2011.12.tar.gz 拷贝到 Ubuntu 主目录下  i.MX6 用户光盘/i.MX6 用户光...

Fedora14 i386下 使用Intel编译器 安装WRF指南

Intel编译器下WRF安装指南                                                                                   ...

GCC编译器中的-I -L -l 选项。

原文链接:http://blog.csdn.net/stpeace/article/details/49408665 在本文中, 我们来聊聊gcc中三个常见的参数, 也即-I(大写的i), ...

深入理解Android 卷I part1

  • 2013年10月30日 10:49
  • 2.46MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:i++,++i, i=i+1 vs编译器上的深入研究
举报原因:
原因补充:

(最多只允许输入30个字)