先通过汇编代码来看看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++作为函数参数时压栈的是取之前遍历函数参数时留下的临时量的值