i++与++i是一样的吗?

您所在的位置:网站首页 pinotwork和pibrowser一样吗 i++与++i是一样的吗?

i++与++i是一样的吗?

2024-07-17 04:06| 来源: 网络整理| 查看: 265

  在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