2012-02-08 128 views
1

我很困惑。自動,靜態和全局變量的分配是在編譯時還是運行時發生的?變量的內存分配

我知道的事情是,在編譯時,源代碼被翻譯成機器語言。

當編譯器找到像int a;這樣的語句時,它會寫入指令。在編譯時是否會發生額外的事情,比如內存分配?

當執行.exe文件時會發生什麼?

計算機(OS)或編譯器是否會在運行時或編譯時分配足夠的內存來保存整數。

另外據說全局變量的地址是編譯時常量。這是什麼意思? 請幫助解決每個問題,特別是最後一個問題。

+1

像'int a;'這樣的聲明並不直接對應於機器指令。 – 2012-02-08 16:13:36

+0

這是功課嗎? – Francois 2012-02-08 16:13:56

+0

這不是我家庭作業的一部分。問題出現在我的腦海裏,爲什麼舊​​的學習會與新的學習衝突。我總是Google它,直到我怪異 – 2012-02-08 16:17:43

回答

6

靜態全局變量在編譯時或運行時分配內存資源。這取決於靜態變量是否爲零初始化,或者它們是否具有初始常量值。舉例來說,這樣的代碼

//global variable with internal linkage 
static int array[100]; 

不會佔用執行體的任何房間......換句話說,編譯器/連接不會在執行該陣列,因爲它不包含任何分配內存。它會留下一個存根,表示何時啓動可執行文件,必須爲該數組分配內存。一旦啓動可執行文件,操作系統就會看到鏈接程序留下的存根,併爲該數組分配和初始化內存(以及堆的其他內存等)。在其他手,因爲它是在編譯時間常數的值初始化

//global variable with internal linkage 
static int array[100] = { 1, 2, 3}; 

將佔用空間的可執行文件。因此,編譯器將在它生成的程序集文件的data部分發出代碼,爲該陣列分配存儲空間。然後鏈接程序將正確地佈置鏈接到最終可執行文件的所有程序集文件的數據段和代碼段。當操作系統將可執行文件加載到內存中時,數組的內存已經是可執行文件內存「腳印」的一部分。

自動變量,因爲它們的代碼執行期間在棧上分配的,在運行時分配。

另外據說全局變量的地址是編譯時間常數。

這是一個有點誤導...用C你可以不知道任何全局變量的確切的內存地址,直到連接器已經創建了可執行文件,操作系統加載可執行文件到內存中。唯一的辦法是如果你手工組裝一個文件並創建一個平臺二進制文件,這個二進制文件被操作系統專門加載到一個給定的地址中,但是現代操作系統不允許你這樣做。相反,全局變量的地址由鏈接器給予佔位符,這樣當操作系統在運行時加載可執行文件時,它們可以用正確的值代替。因此,儘管內存地址在程序運行時不會隨時間變化,但內存地址爲「常量」,但其實際值在編譯時不會被分配。

+0

你只談論全局變量與內部鏈接。全局變量與外部linkage – 2012-02-08 17:07:35

+0

同樣的事情本質上......內部和外部鏈接僅僅決定了來自另一個代碼模塊的內存位置的可見性。 – Jason 2012-02-08 17:11:31

+0

您的意思是一種常量佔位符(地址在OS給定時將是常量)賦予全局變量 – 2012-02-08 17:24:12

0

這裏有一堆問題。在C中,你有堆棧內存和堆內存。全局在堆上。所有非全局的非malloc變量都在堆棧中。將堆棧內存視爲您在函數內部創建的內存。每個函數調用都會爲您的堆棧添加另一個圖層當函數返回時,返回在該函數內部分配的非malloc內存。全局變量的內存位置永遠不會改變,這就是爲什麼它的位置在編譯時可能是靜態的。

0

當編譯器發現如int一個;,它寫入 instruction.Does任何額外的事情發生,如內存分配在 聲明編譯時間?

是的,空間是爲堆棧上的變量保留的。

當執行.exe文件時會發生什麼?

在這裏回答太長。縮小你的問題。

計算機(os)或編譯器是否會分配足夠的內存 在運行時或編譯時保存一個整數。

取決於您如何在代碼上分配內存。

另外據說全局變量的地址是編譯時間 常量。它是什麼意思?

這意味着內存在編譯時被保留,因此全局變量的地址在執行期間不會改變。

0

當編譯器在函數中發現int a;語句時,他寫了類似sub esp,sizeof(int)的東西,並且當程序運行並獲取此行時,它會分配內存。

如果它是一個全球性的varibale,編譯器寫resb指令,該指令告訴操作系統分配內存在加載程序。

1

這取決於變量的類型:

  • 堆棧變量在運行時完成(儘管它們的大小是在編譯時知道,棧內存被保留在函數入口,這使得它運行時分配)。這裏還有一個特別的警告,alloca在運行時從堆棧分配,即使它看起來像它的動態堆內存。

  • 堆變量在運行時分配,通常通過new/malloc,但是,指針的存儲可能仍然在堆棧上。

  • 全局和靜態變量在幾個方面進行分配。初始化的將由編譯器以二進制形式分配,並且它們的初始值(或初始化程序將在啓動對象時調用)。未初始化的數據將通過讀取PE通過OS加載程序分配,這就是爲什麼數據在各個段之間分開的原因,如.rdata,.data & .bss

與被全局/靜態變量

現在,編譯器可以爲他們結合相對或者優先常地址,導致它們在二進制中分配。

1

編譯器生成包含比只是機器指令更多的對象文件(.obj Windows下,.o下 的Unix),並且不是所有 構建體在C++將導致機器指令。當內存分配發生時(至少是正式的)未指定。在實際中, 由於自動和動態對象的數量在編譯 時間(因爲函數可能是遞歸的)時是未知的,所以它們只能在編譯時分配到 ,編譯器將生成代碼來完成此操作(儘管 它通常在 函數中分配全部的自動變量,函數頂部有一個或兩個指令)。另一方面,編譯器 確切知道有多少對象具有靜態生存期。我熟悉的所有實現 的實現都會在目標文件中生成加載程序記錄,最終導致系統加載程序在加載程序時將它們分配爲初始過程映像的一部分 ;在加載的程序中沒有代碼,其中 分配它們。 (如果初始化不是靜態的,將會有代碼 初始化它們。)