i++与++i是一样的吗? |
您所在的位置:网站首页 › pinotwork和pibrowser一样吗 › i++与++i是一样的吗? |
在c语言中,我们经常使用i++和++i,可能都会以为它们是一样的,就是对i进行了加1操作。实际上,对于编译器来说它们又意味着什么?会有何不同呢? 之前我都是认为:i++和++i都是对i进行了加1操作,唯一有区别的是: i++ :先取i的值,再对i加1 ++i :先对i加1,再取i的值 但是仅仅是这些不同吗?通过下面的一段示例代码,你就会急迫地想知道:编译器到底是如何处理i++和++i: int main() { int i = 0; printf("%d,%d,%d\n",i++,--i,i++); return 0; }如果仅仅按照我们刚才的分析: 在上面的代码中,进行i++操作,先获取i的值0再使得i变为1;再对i进行--i操作,此时i又变为0;最后再i++操作,又是获取到i的值0,再进行+1操作变为1。最终,打印的出的结果一定是:0,0,0;
可是程序运行出的结果并不是这样的,显然,编译器并不是像我们之前认为的那样进行处理的,那么这个过程到底发生了什么? 为了更好的理解这个过程,我们先来看两个简单的i++和++i的代码,了解背后所隐藏的细节: 1、编译器中的i++ int main() { int i = 0; printf("%d\n",i++); return 0; }这个很简单,我们知道打印出的结果是:0,
那编译器做了什么,我们通过汇编代码来分析一下:
从汇编代码我们可以看到如下图所示的过程:
这个过程通过5步完成,最后传给printf的参数是从临时量中的值。因此,我们认识到:在执行i++时, (1)编译器向从i的内存空间中把读取到的值传给一个寄存器,寄存器又把值传给一个临时量; (2)接着又把i内存中的值传给另一个寄存器,然后通过这个寄存器进行+1操作,再把结果传给i的内存中,此时i内存中的值已经变为1. (3)最后在传参数给printf函数时,传递的是临时量中的值,而不是i内存中的值; 2、编译器中的++i int main() { int i = 0; printf("%d\n",++i); return 0; }这个很简单,我们知道打印出的结果是:1,
从汇编代码我们可以看到如下图所示的过程: 这个过程通过4步完成,最后传给printf的参数相当于是从i的内存中获取的。因此,我们认识到:在执行++i时, (1)编译器向从i的内存空间中把读取到的值传给一个寄存器(eax),寄存器完成对i的+1操作,再把结果写回i的内存; (2)最后传递给printf的参数值是通过一个寄存器把i内存中的值传递过去的;
小结:看到这里,可以会发现,原来编译器对i++和++i的处理过程是有所不同的:虽然最终的结果都是将i内存中的值完成了+1操作,但是对i++的处理过程中有临时量的参数,并且传递给printf函数的参数是从临时量中获取的,而不是i的内存;而对++i的处理中没有临时量的产生,是直接通过寄存器完成,最后传递给给printf函数的参数是从i的内存中回去的。 通过上面两个简单的函数,让我们知道了编译器对i++和++i的处理过程中的不同,此时我们再回过头看最开始让我们有点疑惑的示例代码,来进一步分析整个过程: int i = 0; 008A13DE mov dword ptr [i],0 printf("%d,%d,%d\n",i++,--i,i++); 008A13E5 mov eax,dword ptr [i] 008A13E8 mov dword ptr [ebp-0D0h],eax 008A13EE mov ecx,dword ptr [i] 008A13F1 add ecx,1 008A13F4 mov dword ptr [i],ecx 008A13F7 mov edx,dword ptr [i] 008A13FA sub edx,1 008A13FD mov dword ptr [i],edx 008A1400 mov eax,dword ptr [i] 008A1403 mov dword ptr [ebp-0D4h],eax 008A1409 mov ecx,dword ptr [i] 008A140C add ecx,1 008A140F mov dword ptr [i],ecx 008A1412 mov esi,esp 008A1414 mov edx,dword ptr [ebp-0D0h] 008A141A push edx 008A141B mov eax,dword ptr [i] 008A141E push eax 008A141F mov ecx,dword ptr [ebp-0D4h] 008A1425 push ecx 008A1426 push 8A5858h 有了上面的基础,我们就会从这段汇编代码中发现:(当然对于printf函数也是一样的,参数的传递是从右向左传的) 编译器对程序中printf("%d,%d,%d\n",i++,--i,i++);一行代码做了大量的操作:可以看到压参操作的指令在比较靠后的位置,所以我们应该知道对于printf函数中i++,--i,i++这3个参数,编译器先完成相应的所有操作,再进行3个参数的压参操作的。 根据我们上面的结论,分析这个过程大致为: (1)i++:(产生临时量a [保存的值为0])完成了对i的+1操作,同时将i内存中的值变为1; (2)--i :不产生临时量,完成对i的-1操作,将将i内存中的值变为0; (3)i++:(产生临时量b [保存的值为0])完成了对i的+1操作,同时将i内存中的值变为1; 最终,将i内存中的值变为1;接下来进行压参操作: i++都有相应的临时量,编译器是将之前临时量中保存的值传给printf函数的; --i 没有相应的临时量,编译器是去取此时i内存中的值【0】传递给printf函数的; 所以最后的结果会是:0,1,0 总结:后置++(--)与前置++(--)虽然都可以完成对变量的+1(-1)操作,但是处理过程是不同的; 前置++(--)会有临时量的产生,而后置++(--)没有临时量的产生;所以如果后置/后置++(--)涉及作为函数参数时,特别是有多次操作时,我们一定要考虑清楚,否则结果可能出乎意料!
|
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |