顯微鏡 下細看字串常量初始化陣列和指標

2021-05-25 08:22:01 字數 2426 閱讀 7444

先看**:

1:  #include "stdafx.h"
2:  #include
3:
4:  

using

namespace std;

5:
6:  

int main(int argc, char** argv)

7:
很多學習c語言的碼農們,對於通過字串常量形式初始化陣列和指標,在頭腦裡沒有乙個清晰的概念,有很多人認為這兩者是等同的,那麼這兩種到底有什麼區別呢,本文通過使用vc6.0下的"顯微鏡" 反編譯器disassembly來仔細的看看隱藏的秘密^_^。

要使用反編譯器,我們首先在程式第一條語句前設定斷點(什麼,不知道怎麼設斷點,莫非你是火星來的programmer!f9設定和取消斷點,f10單行除錯語句,f11能進入函式子程式進行除錯,ctrl+f10 執行到滑鼠指定的行,shift+f11跳出當前函式子程式),然後我們按f5除錯程式,程式會在第乙個設定斷點的地方停下來。當然如果你想從程式的第一條語句開始除錯也可以,直接按f10就ok啦。

那麼我怎麼怎麼調出我們的顯微鏡呢,只需要view->debug window->disassembly就可以看到我們的程式的編譯器產生的**啦。如下:

10:  

1.變數名只在我們編寫**和編譯器編譯的時候用到,一旦編譯過後,生成的**中就不再有變數名的概念了,因為變數已經實實在在的被變數的位址給取代了(變數本不存在,位址取代之)。可通過具體編譯**獲知此結論。 

mov         dword ptr [ebp-4],offset string "abcd" (0043101c)

上面這句話將字串常量「abcd」的位址(offset) 賦值給位址dword ptr [ebp-4](這就是p的位址),同時表明指標變數記憶體大小為4個位元組。

2.字串常量"abcd"的位址是唯一的,因為兩個初始化中string "abcd" (0043101c),表明字串常量儲存在乙個固定的地方,實際上字串常量常常儲存在只允許讀的資料段中rodata中,以防止它被修改。

3.通過字串常量初始化陣列中:mov         eax,[string "abcd" (0043101c)] 這句彙編**將位址0043101c的內容([位址]表示位址中的內容)賦值給eax,因為eax為4個位元組,所以剛好將a、b、c、d四個字元儲存到暫存器eax中。

dword ptr [ebp-0ch],eax。這句

**將暫存器中的四個位元組存放到位址 ebp-0ch中,實際上就是陣列變數a中,只是經過編譯變數名已經不存在了。mov         cl,byte ptr [string "abcd"+4 (00431020)] 這叫將"abcd"+4 (00431020)位址的內容,即字串最後乙個位元組內容'/0',存放在單位元組暫存器cl中。 mov         byte ptr [ebp-8],cl  這裡表示將暫存器中的內容存放在記憶體位元組位址ebp-8中。

上面只是簡單的解釋了彙編**,下面我們通過記憶體空間來窺探為什麼會有ebp-4、ebp-0ch、ebp-8這些奇怪的位址。下面是我用visio畫的記憶體示意圖:

圖一:記憶體示意圖

通過view->debug window->memery可以掉出記憶體分布圖,可以看出0x0043101ch存放的恰好是abcd/0

圖二:memery示意圖

通過view->debug window->registers掉出暫存器檢視,可以知道ebp的位址為0x0012ff80

我們檢視0x0012ff80-0c的位址內容,這個位址從低到高正是我們的陣列a和p的內容

圖四:memery示意圖

圖中需要注意的地方如下:

1.棧的擴充套件是從高位址向位址方向,ebp為棧基位址暫存器(指向棧底),esp為棧偏移位址暫存器(指向棧頂),圖中ebp-4右邊的箭頭表示ebp-4指向的位址,彙編**中的[ebp-4]表示ebp-4指向的內容,即我們被位址取代的變數p=[ebp-4].

2.雖然棧的擴充套件方向是由高到低,但是變數的儲存卻按照位元組序,intel處理機上位元組序為little-endian小字節序, 即小位址儲存低位元組,我們的圖就是選擇的小字節序,所以將p = 0x0043101c 後,ebp-4低位址存放的是低位元組0x1c,由低位址到高位址,依次按照0x1c,0x10,0x43,0x00存放。這裡還有需要注意的一點事,變數的位址總是指它的低位址,所以p的位址是ebp-4,而不是ebp-1.同理陣列內容也是陣列前面的內容存放在低位址,陣列後面的內容存放在高位址。

3.為什麼a的位址是ebp-0ch,不應該是ebp-9嗎,這裡就是編譯器採取了優化訪問方式的位元組對齊aligement方法,使a的位址為ebp-0ch = ebp – 12  。

4.可以看到char * p = "abcd";只是將靜態字串常量的位址賦給了指標變數p,而char a = "abcd";是將靜態常量字串的內容完完整整的拷貝了乙份到棧中。

字串初始化

在c語言程式設計中,當我們宣告乙個字串陣列的時候,常常需要把它初始化為空串。總結起來有以下三種方式 1 char str 10 2 char str 10 3 char str 10 str 0 0 第 1 2 種方式是將str陣列的所有元素都初始化為 0 而第 3 種方式是只將str陣列的第乙個元...

字串初始化

在 裡,經常會用字串進行初始化操作。比如 void func void 對於上面2條初始化語句,它們的區別是什麼呢?1,首先,hello world 是乙個字串常量,存放在靜態常量區。2,str1是乙個字元陣列,分配在棧上,儲存空間由 hello world 的長度 含 0 決定,存放的內容由 he...

字串初始化

字串初始化使用字串初始化操作符即百分號 標記轉化說明符的開始。在 左邊為格式化字串,右邊為被格式化的值。format hello,s.s enough?values world cold print format values hello,world.cold enough?格式化字串的 s部分為轉...