1. 程式人生 > >i++和++i的區別和實現的原理探究

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++作為函式引數時壓棧的是取之前遍歷函式引數時留下的臨時量的值

相關推薦

StringBuffer與StringBuilder的區別實現原理擴容

StringBuffer與StringBuilder的區別,及實現原理 區別 1、StringBuffer 與 StringBuilder 中的方法和功能完全是等價的, 2、只是StringBuffer 中的方法大都採用了 synchronized 

自旋鎖,讀寫鎖順序鎖的實現原理

並且 保護 表達 min 返回 create creat rwlock ini 常用的同步原語鎖,到多核處理器時代鎖已經是必不可少的同步方式之一了。無論設計多優秀的多線程數據結構,都避不開有競爭的臨界區,此時高效的鎖顯得至關重要。鎖的顆粒度是框架/程序設計者所關註的,

AFNetworking 3.0 使用詳解 源碼解析實現原理

數據 syn ria 特定 style conn afn rda gre AFN原理&& AFN如何使用RunLoop來實現的: NSString * requestURL = @"http://119.254.98.136/api/v1/web/

Java的Executor框架執行緒池實現原理

一,Java的Executor框架 1,Executor介面 public interface Executor {     void execute(Runnable command); } Executor介面是Executor框架中最基礎的部分,定義了一個用於

微信自動回覆自動搶紅包實現原理(三):自動搶紅包

經過前兩篇文章的閱讀,我相信大家應該對AccessibilityService有一定的瞭解了,是不是已經按捺不住,想自己動手試試?先別急,可以再看完我這篇文章還不遲,相信你另有收穫的。接下來我們來探索一下自動搶紅包的實現原理。 看了我第二篇微信自動回覆

微信自動回覆自動搶紅包實現原理(二):自動回覆

完成AccessibilityService的配置後,好像無從下手。先別急,先列印一些log看看吧。把下面的方法放在onAccessibilityEvent()裡: private void printEventLog(Accessibilit

(精)Spring IOC核心原始碼學習III:bean標籤自定義標籤實現原理

本文將解析spring bean定義標籤和自定義標籤的解析實現原理。這裡說的標籤僅限於以xml作為bean定義描述符的spring容器,繼承AbstractXmlApplicationContext的一些子 容器,如XmlApplicationContext、ClassPat

C語言中*&的區別-程式碼實現說明

*是指標運算子,可以表示一個變數是指標型別;也可以表示一個指標變數的所指向的儲存單元,可以獲取某個地址儲存的值。 &是取地址符號,既取得某一個變數的地址 int *p=&a;

Sftpftp 區別、工作原理等(彙總ing)

FTP協議安全分析 前 言 FTP(File Transfer Protocol,檔案傳輸協議)是網際網路上常用的協議之一,人們用FTP實現互連網上的檔案傳輸。由於TCP/IP協議族在設計時是處在一個相互信任的 平臺上的,使得在網路安全越來越被重視的今天,TCP/IP協議族的安全性也成為了安全界研究的

Android自動接聽結束通話電話實現原理

轉自:http://bbs.51cto.com/thread-1078059-1.html 一  前言 這兩天要研究類似白名單黑名單以及手勢自動接聽的一些功能,所以呢,自然而然的涉及到怎麼自動接聽/結束通話電話的功能了。 對於自動接聽這一塊,android4.1

java之RunnableThread區別實現方法

1、多執行緒中start()和run()方法的區別 1) start: 用start方法來啟動執行緒,真正實現了多執行緒執行,這時無需等待run方法體程式碼執行完畢而直接繼續執行下面的程式碼。通過呼叫Thread類的 start()方法來啟動一個執行緒,這時

單點登入第三方登入的實現原理

單點登入:       我們的單點登入系統,主要包含了登入驗證,token校驗 、登出、註冊幾大功能,單點登入系統提供了統一的登入和註冊頁面,提供了統一的登入token校驗介面。單點登入的主要原理就是在登入成功以後,生成一個令牌,這個領跑要求每次登入唯一不可重複,我們就簡單的

H5下拉重新整理上拉載入實現原理淺析 (轉載)

前言 在移動端H5網頁中,下拉重新整理和上拉載入更多資料的互動方式出現頻率很高,開源社群也有很多類似的解決方案,如iscroll,pulltorefresh.js庫等。下面是對這兩種常見互動基本實現原理的闡述。 實現原理 下拉重新整理 實現下拉重新整理主要分為三步

Java多執行緒程式設計-(13)-從volatilesynchronized的底層實現原理看Java虛擬機器對鎖優化所做的努力

一、背景 對於Java來說我們知道,Java程式碼首先會編譯成Java位元組碼,位元組碼被類載入器載入到JVM裡,JVM執行位元組碼,最終需要轉化為彙編指令在CPU上進行執行。 Java中所使用

360衛士通知盒子紅包助手的實現原理(NotificationListenerService)

Google在Android 4.3 (API 18)中引入一個新類NotificationListenerService,它的功能很強大,當任何應用彈出通知的時候,它都可以接收到,並且當通知被移除的時候,它也可以接收到資訊,很顯然,我們可以通過這個類來對手機中

Spring IOCSpring AOP的實現原理(原始碼主線流程)

寫在前面      正本文參考了《spring技術內幕》和spring 4.0.5原始碼。本文只描述原理流程的主線部分,其他比如驗證,快取什麼可以具體參考原始碼理解。Spring IOC一、容器初始化      容器的初始化首先是在對應的構造器中進行,在application

深入分析String.internString常量的實現原理

背景 字串型別在實際應用場景中使用非常頻繁,如果為每個字串常量都生成一個對應的String物件,明顯會造成記憶體的浪費,針對這一

知識點 - python 裝飾器@staticmethod@classmethod區別使用

定義 整潔 參數 sel spa elf pri Go assm 1.通常來說,我們使用一個類的方法時,首先要實例化這個類,再用實例化的類來調用其方法 class Test(object): """docstring for Test""" def

hashCode() equals() 區別作用(轉)

person set集合 static out fin 解決 詳細 返回 art 出處:https://www.jianshu.com/p/5a7f5f786b75 本章的內容主要解決下面幾個問題: 1 equals() 的作用是什麽? 2 equal

Java之JSONObject存取值以及HashMap區別, optString()getString()區別他的遍歷方式

結論: 1.JSONObject和HashMap用法上是一樣的,用put()方法存對於的Key-values鍵值對,取可用optString(key)和getString(key),get(key),存入的是什麼型別,取出來的時候就是什麼型別 2**.optString()在沒找到k