試圖用中文、英文等自然語言將 C++ 的指標和引用的異同描述得簡練、通透是一件困難的事情,而閱讀包含指標和引用的反組譯碼代碼是一個好辦法:這絕對是一種無二義性和儘可能簡練的陳述。
比如下述代碼
void main(void)
{
int x1=0,*ptrx1=&x1;
int x2=0,&refx2=x2;
(*ptrx1)++; //關注對變數的操作
refx2++;
printf("x1=%d,x2=%d/n",x1,x2);
}
執行後,通過指標及引用對變數的間接操作使 x1 和 x2 都增加了 1 ,不過究竟是如何?的?我們一起分析反組譯碼代碼:
(*ptrx1)++;
mov edx,dword ptr [ebp-8] ;先讀取 x1 的指標到 edx
mov eax,dword ptr [edx] ;然後讀取 x1 的值到 eax
add eax,1 ;在 eax 中將 x1 的值增 1
mov ecx,dword ptr [ebp-8] ;再次讀取 x1 的指標到 ecx
mov dword ptr [ecx],eax ;將增 1 後的變數值送回
refx2++;
mov edx,dword ptr [ebp-10h]
mov eax,dword ptr [edx]
add eax,1
mov ecx,dword ptr [ebp-10h]
mov dword ptr [ecx],eax
很顯然,通過引用將被引用的變數增 1 和通過指標將其指向的變數增 1 的機器代碼完全一致,這說明引用形式上以操作變數的簡單形式、暗地裡採用了和指標一樣的方式:通過地址定位和操作變數。
除了通過地址定位和操作變數外,引用不提供對地址的操作,缺乏指標訪問變數的靈活性。引用的優勢是簡練,比較適合函數的參數傳遞,比如:
void chg(int* x,int& y) //前一個參數是指標、後一個是引用
{
x++;
y++;
}
int main(void)
{
int mx=0,my=0;
chg(&mx,my);
}
分析反組譯碼代碼:
chg(&mx,my); //指標和引用都通過地址傳遞參數
lea eax,[ebp-8]
push eax
lea ecx,[ebp-4]
push ecx
call @ILT+0(chg) (00401005)
x++; // x++ 修改地址
mov eax,dword ptr [ebp+8]
add eax,4
mov dword ptr [ebp+8],eax
y++; // y++ 通過地址修改變數
mov ecx,dword ptr [ebp+0Ch]
mov edx,dword ptr [ecx]
add edx,1
mov eax,dword ptr [ebp+0Ch]
mov dword ptr [eax],edx
顯然:
① 指標和引用都通過地址定位和操作變數,這是共同點;
② 引用以操作普通變數的形式操作變數:簡略;不具備操作變數地址的功能:不及指標靈活和強大——這是指標和引用的不同點。
通過上述分析,不知道是否可以這樣認為:引用以簡略的方式取代了某些條件下指標的作用;引用涵蓋了指標的部分功能;指標可以取代引用,而引用不能取代指標。
上述“分析”過程其實應該叫做“解讀”,因為反組譯碼代碼已經對指標和引用的功能給出了絕對無二義性的、儘可能簡練和人性化的描述,對知曉組合語言的人而言應該是毫無障礙的——這就是我順便想說的:組合語言是研究進階語言的萬能鑰匙。