i++和++i的区别和实现的原理探究

先通过汇编代码来看看i++和++i有什么不同

i++;
00E97EA5  mov         eax,dword ptr [i]  
00E97EA8  add         eax,1  
00E97EAB  mov         dword ptr [i],eax  
	++i;
00E97EAE  mov         eax,dword ptr [i]  
00E97EB1  add         eax,1  
00E97EB4  mov         dword ptr [i],eax 


对比来看好像没有什么多大的区别

但是执行下面的代码:
int  main()
{
	int i = 0;
	//i++ = 100;//直接报错,编译出错: error C2106: “=”: 左操作数必须为左值
	++i=100;//通过,没有错误
	printf("%d", i);//直接打印100
	return 0;
}

 
  

分析原因:

可以认为编译器在处理i++和++i的方式不同

i++完成之后返回的是右值也就是一个常量

++i完成之后返回的是左值也就是i的内存,对++i赋值相当于给i赋值

所以最后的结果是100.而对i++赋值则直接报错再来看一个问题:

int fun(int a, int b)
{
	printf("%d  %d", a, b);
	return 0;
}
int  main()
{
	int i = 0;
	fun(i++, ++i);
	system("pause");
	return 0;
}
按照函数的传参顺序,你可能会认为fun函数打印的值是1,1

但是实际上打印的确是1,2

那么这是为什么?

让我们通过反汇编去查看调用fun函数的时候编译器究竟是怎么做的?

	fun(i++, ++i);
00B47EA5  mov         eax,dword ptr [i]//从内存取i的值到eax寄存器  
00B47EA8  add         eax,1 //eax寄存器的值+1操作
00B47EAB  mov         dword ptr [i],eax//eax寄存器的值写回i的内存
//这是在从右往左遍历第一个参数++i
00B47EAE  mov         ecx,dword ptr [i] //从内存取i的值写到ecx寄存器
00B47EB1  mov         dword ptr [ebp-0D0h],ecx//把ecx寄存器的值放到新开辟的临时量中 
00B47EB7  mov         edx,dword ptr [i]//从内存取i的值到另一个edx寄存器  
00B47EBA  add         edx,1 //eax寄存器的值+1操作 
00B47EBD  mov         dword ptr [i],edx//eax寄存器的值写回i的内存
 //这是在从右往左遍历第二个参数i++
以下是遍历完所有的参数之后进行函数的参数压栈的操作:
00B47EC0  mov         eax,dword ptr [i]  
00B47EC3  push        eax  
//第一个参数:是把内存中的i压栈
00B47EC4  mov         ecx,dword ptr [ebp-0D0h]  
00B47ECA  push        ecx  
//第二个参数:把之前遍历第二个参数的临时量压栈
00B47ECB  call        fun (0B41433h)//调用函数  
00B47ED0  add         esp,8 


总结:

函数在形参压栈之前进行,参数的遍历工作:也就是把所有带表达式的参数确定下调用的具体对象或者说是具体的值。

1、++i作为函数参数时压栈的是取内存中最后i的值

2、i++作为函数参数时压栈的是取之前遍历函数参数时留下的临时量的值

你可能感兴趣的:(C/C++)