轉載請註明出處
作者:小馬
很多人都知道指標訪問比數組訪問效率高, 但很少人明白其中的原理, 這篇文章從彙編層級上分析一下原因.
我用一個"reverse"函數來作為例子, 分別用指標和數組的形式來實現這個函數.
//指標訪問void reverse(char *pStr,int nLen){ char *pStart=pStr;//指向字串開始 char *pEnd=pStr+nLen-1;//指向字串結尾 char chTmp; while(pEnd > pStart) { chTmp = *pStart; *pStart = *pEnd; *pEnd = chTmp; pStart++; pEnd--; }}
上面的函數在vc6下的反組譯碼代碼,我加了一些注釋方便理解
19: void reverse(char *pStr,int nLen)20: {00401070 push ebp00401071 mov ebp,esp00401073 sub esp,4Ch00401076 push ebx00401077 push esi00401078 push edi00401079 lea edi,[ebp-4Ch]0040107C mov ecx,13h00401081 mov eax,0CCCCCCCCh00401086 rep stos dword ptr [edi]//調用子函數時進堆棧儲存資訊. 00401088 mov eax,dword ptr [ebp+8]0040108B mov dword ptr [ebp-4],eax//char *pStart=pStr;0040108E mov ecx,dword ptr [ebp+0Ch]00401091 mov edx,dword ptr [ebp+8]00401094 lea eax,[edx+ecx-1]00401098 mov dword ptr [ebp-8],eax//char *pEnd=pStr+nLen-1; 0040109B mov ecx,dword ptr [ebp-8]0040109E cmp ecx,dword ptr [ebp-4]//while(pEnd > pStart)004010A1 jbe reverse+61h (004010d1) 004010A3 mov edx,dword ptr [ebp-4]//chTmp = *pStart;004010A6 mov al,byte ptr [edx]//取一個位元組004010A8 mov byte ptr [ebp-0Ch],al 004010AB mov ecx,dword ptr [ebp-4]//*pStart = *pEnd;004010AE mov edx,dword ptr [ebp-8]004010B1 mov al,byte ptr [edx]//從pEnd中取一個位元組004010B3 mov byte ptr [ecx],al 004010B5 mov ecx,dword ptr [ebp-8]// *pEnd = chTmp;004010B8 mov dl,byte ptr [ebp-0Ch]004010BB mov byte ptr [ecx],dl 004010BD mov eax,dword ptr [ebp-4]//pStart++;004010C0 add eax,1004010C3 mov dword ptr [ebp-4],eax 004010C6 mov ecx,dword ptr [ebp-8]//pEnd--;004010C9 sub ecx,1004010CC mov dword ptr [ebp-8],ecx}
//數組訪問void reverse(char *pStr,int nLen){ int i = 0; int j = nLen-1; char chTmp; while(j>i) { chTmp=pStr[i]; pStr[i]=pStr[j]; pStr[j]=chTmp; i++; j--; }}
這是上面代碼的反組譯碼
19: void reverse(char *pStr,int nLen)20: {004010D0 push ebp004010D1 mov ebp,esp004010D3 sub esp,4Ch004010D6 push ebx004010D7 push esi004010D8 push edi004010D9 lea edi,[ebp-4Ch]004010DC mov ecx,13h004010E1 mov eax,0CCCCCCCCh004010E6 rep stos dword ptr [edi]004010E8 mov dword ptr [ebp-4],0004010EF mov eax,dword ptr [ebp+0Ch]004010F2 sub eax,1004010F5 mov dword ptr [ebp-8],eax 004010F8 mov ecx,dword ptr [ebp-8]004010FB cmp ecx,dword ptr [ebp-4]004010FE jle reverse+6Ah (0040113a) 00401100 mov edx,dword ptr [ebp+8] //注意這裡00401103 add edx,dword ptr [ebp-4] 00401106 mov al,byte ptr [edx]00401108 mov byte ptr [ebp-0Ch],al0040110B mov ecx,dword ptr [ebp+8] //注意這裡0040110E add ecx,dword ptr [ebp-4] 00401111 mov edx,dword ptr [ebp+8] //注意這裡00401114 add edx,dword ptr [ebp-8] 00401117 mov al,byte ptr [edx]00401119 mov byte ptr [ecx],al0040111B mov ecx,dword ptr [ebp+8] //注意這裡0040111E add ecx,dword ptr [ebp-8] 00401121 mov dl,byte ptr [ebp-0Ch]00401124 mov byte ptr [ecx],dl00401126 mov eax,dword ptr [ebp-4]00401129 add eax,10040112C mov dword ptr [ebp-4],eax0040112F mov ecx,dword ptr [ebp-8]00401132 sub ecx,100401135 mov dword ptr [ebp-8],ecx}
兩個函數反組譯碼後的代碼基本是一致的,但第二段彙編中多了幾個add語句, 這是因為在用數組下標的形式訪問字串時,總要對數組的首地址做加減操作才能定位到想要的值, 而指標的實現則一開始就copy了一個首地址,不需要再用加減來定位.顯然在這個例子中,用指標來實現reverse函數效率要高.