C語言內存分配
C語言內存布局
程序執行的時候一定會佔用內存空間。為了能夠更好地管理內存空間,我們通常要對內存進行布局,將其劃分為不同的功能塊。這有利於提高執行的效率、提高空間利用率、提高代碼的安全性等。
在PC中,操作系統會在RAM中開闢一段連續的內存空間供程序使用。我們把內存空間從低地址位到高地址位,劃分為五大段,如下圖所示。
Text(RO): code and constant data
- 代碼段存放彙編產生的機器代碼。
- 為了防止數據溢出導致覆蓋代碼,將Text放在最低地址處。
- 代碼段是可以共享的,數據段是私有的,當運行多個程序的副本時,只需要保存一份代碼段部分。這在現代的操作系統裏面佔據了極為重要的地位,特別是在有動態鏈接的系統中,可以節省大量的內存。
Data(RW): initialized global and static variables
Data段在可執行文件中,由系統從可執行文件中加載。
BSS(RW): uninitialized global and static variables
BSS段中的變量都會被初始化為確定的值0,這些初始化的0不需要存儲在可執行文件中,而只需要在ELF文件頭部的Section Table中說明BSS空間大小,在Symbol Table中說明符號即可。當文件加載運行時,才分配空間以及初始化。因此,BSS段不佔用任何的磁盤空間。
Heap(RW): dynamic memory
- 在程序運行時由編譯器自動分配。
- 用來存儲函數調用時的臨時信息的結構,如函數調用所傳遞的參數、函數的返回地址、函數的局部變量等。
- 只是分配空間,並未對其初始化。因此局部變量必須要手動初始化。
- 連續的地址。
- 向低地址增長。這樣棧空間的起始位置就能確定下來,動態的調整棧空間大小也不需要移動棧內的數據。
Stack(RW): local variables
- 在程序運行時由程序員自主分配。
- 不連續的地址。因為其是使用鏈表來分配的。
- 向高地址增長。這樣做內存管理相對要簡單些。
嵌入式C語言內存布局
嵌入式的內存是很寶貴的。我們不可能像PC那樣將所有的段全部放在RAM中。而應根據數據的特點,將只讀的部分存入ROM中,將讀寫的部分存入RAM中。
Keil-MDK在編譯後,會將程序分為四個部分。
- Code: Code in Text
- RO-data: Constant data in Text
- RW-data: Data
- ZI-data: BSS + Heap + Stack
將這四個部分分別存入RAM和ROM中。
- ROM: Code + RO-data + RW-data
- RAM: RW-data + ZI-data
ROM中還要存RW,因為掉電後RAM中所有數據都丟失了,每次上電RAM中的數據是被重新賦值的,而這些固定的初始值就是存儲在ROM中的。
ROM中的指令至少應該有這樣的功能:
- 將RW從ROM中搬到RAM中,因為RW是變量,變量不能存在ROM中。
- 將ZI所在的RAM區域全部清零,因為ZI區域並不在Image中,所以需要程序根據編譯器給出的ZI地址及大小來將相應得RAM區域清零。ZI中也是變量,同理:變量不能存在ROM中。
char* 和 char[]
char* s = "string"; //定義了一個指針,指向了字符串常量。存在Text段中。會有warning,因為指針類型是可以改變的,而常量是不能改變的。
const char*s = "string"; //定義了一個常量指針,指向了字符串常量。存在Text段中。
char s[] = "string"; //定義了一個數組,數組裡存儲着字符串。存在Data段中。