首先三者都是等价的操作,三者的效率也都是等价的,这是vs2010的反汇编,三者都被转成相同的汇编代码:
01041375 mov eax,dword ptr [i]01041378 add eax,10104137B 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;
------->
00B94295 mov eax,dword ptr [i]
00B94298 mov dword ptr [ebp-0D0h],eax
00B9429E mov ecx,dword ptr [i]
00B942A1 add ecx,1
00B942A4 mov dword ptr [i],ecx
00B942A7 mov esi,esp
00B942A9 mov edx,dword ptr [__imp_std::endl (0B9A314h)]
00B942AF push edx
00B942B0 mov edi,esp
00B942B2 mov eax,dword ptr [ebp-0D0h]
00B942B8 push eax
00B942B9 mov ecx,dword ptr [__imp_std::cout (0B9A318h)]
00B942BF call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0B9A31Ch)]
00B942C5 cmp edi,esp
00B942C7 call @ILT+395(__RTC_CheckEsp) (0B91190h)
00B942CC mov ecx,eax
00B942CE call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0B9A300h)]
00B942D4 cmp esi,esp
00B942D6 call @ILT+395(__RTC_CheckEsp) (0B91190h)
00B94298 mov dword ptr [ebp-0D0h],eax
00B9429E mov ecx,dword ptr [i]
00B942A1 add ecx,1
00B942A4 mov dword ptr [i],ecx
00B942A7 mov esi,esp
00B942A9 mov edx,dword ptr [__imp_std::endl (0B9A314h)]
00B942AF push edx
00B942B0 mov edi,esp
00B942B2 mov eax,dword ptr [ebp-0D0h]
00B942B8 push eax
00B942B9 mov ecx,dword ptr [__imp_std::cout (0B9A318h)]
00B942BF call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0B9A31Ch)]
00B942C5 cmp edi,esp
00B942C7 call @ILT+395(__RTC_CheckEsp) (0B91190h)
00B942CC mov ecx,eax
00B942CE call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0B9A300h)]
00B942D4 cmp esi,esp
00B942D6 call @ILT+395(__RTC_CheckEsp) (0B91190h)
如红色标注,发现编译器在i++的基本汇编代码中插入了一句,即先将取出来的i的值存入临时变量中,然后在打印的时候从临时变量中取出压进输出栈。
cout<<++i<<endl;
--------->
00CA42DB mov eax,dword ptr [i]
00CA42DE add eax,1
00CA42E1 mov dword ptr [i],eax
00CA42E4 mov esi,esp
00CA42E6 mov ecx,dword ptr [__imp_std::endl (0CAA314h)]
00CA42EC push ecx
00CA42ED mov edi,esp
00CA42EF mov edx,dword ptr [i]
00CA42F2 push edx
00CA42F3 mov ecx,dword ptr [__imp_std::cout (0CAA318h)]
00CA42F9 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0CAA31Ch)]
00CA42FF cmp edi,esp
00CA4301 call @ILT+395(__RTC_CheckEsp) (0CA1190h)
00CA4306 mov ecx,eax
00CA4308 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0CAA300h)]
00CA430E cmp esi,esp
00CA4310 call @ILT+395(__RTC_CheckEsp) (0CA1190h)
发现,编译器并没有在++i的基本汇编中插入任何东西,而是在要打印的时候直接从变量i中取出压进输出栈。
知道这两点不同就可以很好的理解上述的奇怪现象。
还是需要记住两点的是:
1、在整个输出语句中,都是先对所有的表达式求值后(保存相应的输出信息)再执行输出操作。
2、cout<<i 这种样式的输出只是调用operator <<成员函数的简单形式,
下面一个一个汇编代码来解析:
cout<<i++<<" "<<i++<<endl;
--------------->
00CA4315 mov eax,dword ptr [i]
00CA4318 mov dword ptr [ebp-0D0h],eax
00CA431E mov ecx,dword ptr [i]
00CA4321 add ecx,1
00CA4324 mov dword ptr [i],ecx
00CA4327 mov edx,dword ptr [i]
00CA432A mov dword ptr [ebp-0D4h],edx
00CA4330 mov eax,dword ptr [i]
00CA4333 add eax,1
00CA4336 mov dword ptr [i],eax
00CA4339 mov esi,esp
00CA433B mov ecx,dword ptr [__imp_std::endl (0CAA314h)]
00CA4341 push ecx
00CA4342 mov edi,esp
00CA4344 mov edx,dword ptr [ebp-0D0h]
00CA434A push edx
00CA434B push offset string " " (0CA7830h)
00CA4350 mov ebx,esp
00CA4352 mov eax,dword ptr [ebp-0D4h]
00CA4358 push eax
00CA4359 mov ecx,dword ptr [__imp_std::cout (0CAA318h)]
00CA435F call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0CAA31Ch)]
00CA4365 cmp ebx,esp
00CA4367 call @ILT+395(__RTC_CheckEsp) (0CA1190h)
00CA436C push eax
00CA436D call std::operator<<<std::char_traits<char> > (0CA1145h)
00CA4372 add esp,8
00CA4375 mov ecx,eax
00CA4377 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0CAA31Ch)]
00CA437D cmp edi,esp
00CA437F call @ILT+395(__RTC_CheckEsp) (0CA1190h)
00CA4384 mov ecx,eax
00CA4386 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0CAA300h)]
00CA438C cmp esi,esp
00CA438E call @ILT+395(__RTC_CheckEsp) (0CA1190h)
红色部分即为核心,首先计算第二个i++表达式,再计算第一个,保存信息到临时变量中,即dword ptr [ebp-0D0h] 和dword ptr [ebp-0D4h]中,完成后,先将第二个其值从临时变量中取出压入输出栈,再操作第一个。
cout<<i++<<" "<<++i<<endl;
----------------->
00CA43CA mov eax,dword ptr [i]
00CA43CD add eax,1
00CA43D0 mov dword ptr [i],eax
00CA43D3 mov ecx,dword ptr [i]
00CA43D6 mov dword ptr [ebp-0D0h],ecx
00CA43DC mov edx,dword ptr [i]
00CA43DF add edx,1
00CA43E2 mov dword ptr [i],edx
00CA43E5 mov esi,esp
00CA43E7 mov eax,dword ptr [__imp_std::endl (0CAA314h)]
00CA43EC push eax
00CA43ED mov edi,esp
00CA43EF mov ecx,dword ptr [i]
00CA43F2 push ecx
00CA43F3 push offset string " " (0CA7830h)
00CA43F8 mov ebx,esp
00CA43FA mov edx,dword ptr [ebp-0D0h]
00CA4400 push edx
00CA4401 mov ecx,dword ptr [__imp_std::cout (0CAA318h)]
00CA4407 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0CAA31Ch)]
00CA440D cmp ebx,esp
00CA440F call @ILT+395(__RTC_CheckEsp) (0CA1190h)
00CA4414 push eax
00CA4415 call std::operator<<<std::char_traits<char> > (0CA1145h)
00CA441A add esp,8
00CA441D mov ecx,eax
00CA441F call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0CAA31Ch)]
00CA4425 cmp edi,esp
00CA4427 call @ILT+395(__RTC_CheckEsp) (0CA1190h)
00CA442C mov ecx,eax
00CA442E call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0CAA300h)]
00CA4434 cmp esi,esp
00CA4436 call @ILT+395(__RTC_CheckEsp) (0CA1190h)
这个就是我们不明白其操作原理的最奇怪的例子了,和之前解释的一样,将++i的输出信息压栈的时候是直接从变量i中取出来的值,所以是2(表达式全都计算完的结果),而i++则是保存的临时值(计算i++表达式时保存的临时值)。
知道了这些,下面的两个例子就很好解释了。
cout<<++i<<" "<<++i<<endl;
//2 2
i=0;
cout<<++i<<" "<<i++<<endl;
//2 0
结论:无论怎么样,++i的打印值都是全部计算完的结果,i++要看位置而定。
但是为什么会这样?还是不得而知。