關於書上說的“編譯的時候分配記憶體”
關於書上說的“編譯的時候分配記憶體”
一下均為網路上收集的資料:
1、所謂在編譯期間分配空間指的是靜態分配空間(相對於用new動態申請空間),如全域性變數或靜態變數(包括一些複雜型別的常量),它們所需要的空間大小可以 明確計算出來,並且不會再改變,因此它們可以直接存放在可執行檔案的特定的節裡(而且包含初始化的值),程式執行時也是直接將這個節載入到特定的段中,不 必在程式執行期間用額外的程式碼來產生這些變數。
其實在執行期間再看“變數”這個概念就不再具備編譯期間那麼多的屬性了(諸如名稱,型別,作用域,生存期等等),對應的只是一塊記憶體(只有首址和大小), 所以在執行期間動態申請的空間,是需要額外的程式碼維護,以確保不同變數不會混用記憶體。比如寫new表示有一塊記憶體已經被佔用了,其它變數就不能再用它了; 寫delete表示這塊記憶體自由了,可以被其它變數使用了。(通常我們都是通過變數來使用記憶體的,就編碼而言變數是給記憶體塊起了個名字,用以區分彼此)
記憶體申請和釋放時機很重要,過早會丟失資料,過遲會耗費記憶體。特定情況下編譯器可以幫我們完成這項複雜的工作(增加額外的程式碼維護記憶體空間,實現申請和釋 放)。從這個意義上講,區域性自動變數也是由編譯器負責分配空間的。進一步講,記憶體管理用到了我們常常掛在嘴邊的堆和棧這兩種資料結構。
最後對於“編譯器分配空間”這種不嚴謹的說法,你可以理解成編譯期間它為你規劃好了這些變數的記憶體使用方案,這個方案寫到可執行檔案裡面了(該檔案中包含若干並非出自你大腦衍生的程式碼),直到程式執行時才真正拿出來執行。
2、編譯其實只是一個掃描過程,進行詞法語法檢查,程式碼優化而已,編譯程式越好,程式執行的時候越高效。 我想你說的“編譯時分配記憶體”是指“編譯時賦初值”,它只是形成一個文字,檢查無錯誤,並沒有分配記憶體空間。
當你執行時,系統才把程式匯入記憶體。一個程序(即執行中的程式)在主要包括以下五個分割槽: 棧、堆、bss、data、code
程式碼(編譯後的二進位制程式碼)放在code區,程式碼中生成的各種變數、常量按不同型別分別存放在其它四個區。系統依照程式碼順序執行,然後依照程式碼方案改變或呼叫資料,這就是一個程式的執行過程。
3、編譯時分配記憶體 --------------- 編譯時是不分配記憶體的。此時只是根據宣告時的型別進行佔位,到以後程式執行時分配記憶體才會正確
執行時分配記憶體 --------------- 這是對的,執行時程式是必須調到“記憶體”的。因為CPU(其中有多個暫存器)只與記憶體打交道的。程式在進入實際記憶體之前要首先分配實體記憶體。
編譯過程 -------------- 只能簡單說一下,因為如果要詳細的話,就是一本書了《編譯原理》。編譯器能夠識別語法,資料型別等等。然後逐行逐句檢查編譯成二進位制資料的obj檔案,然後再由連結程式將其連結成一個EXE檔案。此時的程式是以EXE檔案的形式存放在磁碟上。
執行過程 -------------- 當執行這個EXE檔案以後,此程式就被載入到記憶體中,成為程序。此時一開始程式會初始化一些全域性物件,然後找到入口函式(main()或者WinMain()),就開始按程式的執行語句開始執行。此時需要的記憶體只能在程式的堆上進行動態增加/釋放了。
int main()
{ int a =0; //全域性初始化區
char*p1; //全域性未初始化區
int main() {
int b; //棧
char s[] = \"abc\"; //棧
char*p2; //棧
char*p3 = \"123456\"; //123456\\0在常量區,p3在棧上。
staticint c =0;//全域性(靜態)初始化區
p1 =newchar[10];
p2 =newchar[20];
//分配得來得和位元組的區域就在堆區。
strcpy(p1, \"123456\"); //123456\\0放在常量區,編譯器可能會將它與p3所指向的\"123456\"優化成一個地方。
}