在c/c++語言中,爲什麼c[5] == 5[c]

博客轉載請註明原地址: http://blog.csdn.net/sunliymonkey/article/details/48139183

問題:在c/c++語言中,爲什麼c[5] == 5[c]?

  這個問題,當初是在德問上看見的,起初自己也不知道其機理,猜測與c語言的編譯機制有關,於是通過反彙編、猜測、驗證,最終找到了原由。

下面是我分析該問題的過程,首先來看一段關於數組的代碼:

#include<iostream>
using namespace std;
int main()
{
    int a[5];
    for(int i = 1; i < 5; i++)
    {   
        a[i] = i + 5;
    }
    a[3] = 11;
    3[a] = 15;
    cout << a[3] << endl;
    system("pause");
    return 0;
}   

使用Microsoft Visual 2010對代碼進行反彙編:

7:  {   
8:      a[i] = i + 5;
00251B80 8B 45 D8      mov   eax,dword ptr [i]  
00251B83 83 C0 05      add   eax,5              // eax = i + 5
00251B86 8B 4D D8      mov   ecx,dword ptr [i]  // 用ecx存放a[i]下標i的值
00251B89 89 44 8D E4   mov  dword ptr [ebp+ecx*4-1Ch],eax // 將eax的值傳給a[i]  
9: }

根據上面的彙編代碼,我們可以發現編譯器對於a[i]的彙編表示:

    a[i]:  dword ptr [ebp+ecx*4-1Ch]

  其中dword,表示雙字(四個字節);ptr,pointer縮寫,表示指針;[addr]中的addr表示地址位置。整個式子表示從位於ebp+ecx*4-1Ch的地址處,提取變量大小爲4個字節的變量值,與a[i]進行對比,可以猜測:

    a[i]    <--->    [ebp+ecx*4-1Ch]
    a       <--->    ebp - 1Ch   //數組首地址
    i       <--->    ecx         //數組下標
    int     <--->    4           //變量大小

這裏寫圖片描述

通過Microsoft Visual 2010對比aebp-1Ch的值,可以發現它們相等,也就證明了我們上面的對應關係,總結出編譯器對於數組的解釋:

    ptr [數組首地址 + 數組下標 * sizeof(變量類型)]

貌似這個結論,比較顯然,但是如果按照這個結論來看:

  • a[3]翻譯爲: ptr [ a + 3 * sizeof(int) ]

  • 3[a]翻譯爲: ptr [ 3 + a * sizeof(int) ]

      如此來看,兩者不應該是一樣的,但是實際運行程序發現,兩者確實相等。這讓我們感覺到編譯器非常聰明,能夠識別出a纔是真正的數組首地址,3纔是真正的數組下標。考慮到編譯器的才能是由我們程序員所賦予,顯然其無法真正識別出誰是數組首地址,而是通過預設的指導規則得到。

      在這裏,3a,對編譯器來講,前者是一個常數,後者是一個指針變量。從更高層次來看a[i][i]a,兩者均爲變量,不過其中一個是整數類型,另外一個是指針類型。能夠猜測到,編譯器應該是將指針變量識別爲數組首地址,而剩餘的變量值作爲數組下標

接下來我們做以下實驗進行驗證:

    int a[5];
    int *p = a;
    int i = 2 , b = &a;
    //a: 數組首地址
    i[a] = 1;   // 正確
    2[a] = 1;   // 正確
    (i+2)[a+1]=1; // 正確

    //p: int指針變量
    i[p] = 1;   // 正確
    2[p] = 1;   // 正確
    (i+2)[p+1]=1; // 正確

    //無指針變量
    b[2] = 3;   // 失敗 error C2109: 下標要求數組或指針類型
    2[b] = 4;   // 失敗 error C2109: 下標要求數組或指針類型
    i[b] = 5;   // 失敗 error C2109: 下標要求數組或指針類型
    b[i] = 6;   // 失敗 error C2109: 下標要求數組或指針類型

  因此編譯器對於數組的處理時,必須要有一個指針變量作爲基址,其它數值作爲數組下標。你可能不禁會問:如果存在兩個指針變量,怎麼辦? 按照上面的推測,存在兩個指針變量,編譯器貌似是無法處理的,實驗驗證也表明,存在多個指針變量,將會報錯:

    int a[5],b[5];
    a[b+2] = 4;  // 失敗  error C2107: 非法索引,不允許間接尋址

至此問題分析完畢,總結如下:

  1. a[i] 與 i[a]的含義一樣

  2. 數組a[i]被解釋爲: ptr [數組首地址 + 下標 * sizeof(變量類型)]

  3. 表達式中必須出現一個指針變量,無論其位置如何,其被視爲數組首地址,剩餘的值作爲數組下標

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章