這個問題,當初是在德問上看見的,起初自己也不知道其機理,猜測與c語言的編譯機制有關,於是通過反彙編、猜測、驗證,最終找到了原由。
下面是我分析該問題的過程,首先來看一段關於陣列的**:
#include
using
namespace
std;
int main()
a[3] = 11;
3[a] = 15;
cout
<< a[3] << endl;
system("pause");
return
0;}
使用microsoft visual 2010對**進行反彙編:
7:
根據上面的彙編**,我們可以發現編譯器對於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對比a
與ebp-1ch
的值,可以發現它們相等,也就證明了我們上面的對應關係,總結出編譯器對於陣列的解釋:
ptr [陣列首位址 + 陣列下標 * sizeof(變數型別)]
貌似這個結論,比較顯然,但是如果按照這個結論來看:
接下來我們做以下實驗進行驗證:
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: 非法索引,不允許間接定址
至此問題分析完畢,總結如下:
a[i] 與 i[a]的含義一樣
表示式中必須出現乙個指標變數,無論其位置如何,其被視為陣列首位址,剩餘的值作為陣列下標
在C語言中 巨集定義是什麼?
巨集定義是c提供的三種預處理功能的其中一種,這三種預處理包括 巨集定義 檔案包含 條件編譯 巨集定義又稱為巨集代換 巨集替換,簡稱 巨集 格式 define 識別符號 字串 其中的識別符號就是所謂的符號常量,也稱為 巨集名 預處理 預編譯 工作也叫做巨集展開 將巨集名替換為字串。掌握 巨集 概念的關...
在c語言中是什麼意思?
是乙個整體,它是用於指向結構體子資料的指標,用來取子資料。換種說法,如果我們在c語言中定義了乙個結構體,然後申明乙個指標指向這個結構體,那麼我們要用指標取出結構體中的資料,就要用到 舉個栗子 問題中的p p a,意思是將p指向的乙個結構體例項中的自資料a賦值給p.首先定義乙個結構體 struct f...
C語言中為什麼要清除 bss段
bss段裡的內容 顯示初始化為0或者未顯示初始化的全域性變數 顯示初始化為0或者未顯示初始化的static區域性變數。為什麼要清除.bss段 c語言程式在編譯完成後,初始化為非零的全域性變數存放在.data段,而未初始化或初始化為0的全域性變數存放在.bss段中。在生成的可執行檔案中,只有.data...