如果要加入此計劃:
1、
方式1
:加入
QQ
群:
93684322
。
2、
方式2
:加入
CSDN
群組:
DS計劃
。
1.1 變數儲存域1.1.1 一個樣本
pang123hui首先提供了一個網上流傳的學習程式碼範例:
int a = 0; //全域區
void main()
{
int b; //棧
char s[] = “abc”; //s在棧,abc在文字常量區
char *p1,*p2; //棧
char *p3 = "123456"; //123456在常量區,p3在棧上
static int c =0; //全域區
p1 = (char *)malloc(10); //p1在棧,分配的10位元組在堆
p2 = (char *)malloc(20); //p2在棧,分配的20位元組在堆
strcpy(p1, "123456"); //123456放在常量區
}
這個程式碼範例中出現了“全域區”,“棧”,“文字常量區”,“堆”等詞語。為了統一,我們使用《C專家編程》中的說法:堆棧段,BSS段,資料區段,文本段。
各個段的作用如下:
1、 文本段:包含程式的指令,它在程式的執行過程中一般不會改變。
2、 資料區段:包含了經過初始化的全域變數和靜態變數,以及他們的值。
3、 BSS段:包含未經初始化的全域變數和靜態變數。
4、 堆棧段:包含了函數內部聲明的局部變數。
當然,上面段的作用不僅於此,具體的作用會在下面的知識點中介紹。
1.1.2 通過代碼測試變數的儲存位置
Linux下可以通過系統命令“size”查看可以執行程式各個段的大小。但是,可執行程式中的段結構和運行中程式在記憶體中的段結構並不完全相同,但是有一定的映射關係。具體如所示(圖片資訊來自《C專家編程》):
下面通過程式碼範例和“size”來研究變數的儲存地區。
test.c
int main()
{
return 1;
}
編譯,並且查看可執行程式各個段的大小:
更改test.c:
int g_data;
int main()
{
return 1;
}
編譯,並且查看可執行程式各個段的大小:
可以發現,文本段,資料區段都沒有發送變化,而BSS段增加了4個位元組。
結論1:未初始化的全域變數儲存在BSS段中
繼續:
int g_data = 1;
int main()
{
return 1;
}
編譯:
可以發現,BSS段和文本段相同,而資料區段增加了4個位元組。
結論2:經過初始化的全域變數儲存在資料區段中
繼續:
int main()
{
static int g_data;
return 1;
}
編譯:
可以發現,文本段,資料區段都沒有發送變化,而BSS段增加了4個位元組。
結論3:未初始化的靜態變數儲存在BSS段中
繼續:
int main()
{
static int g_data = 1;
return 1;
}
編譯:
可以發現,BSS段和文本段相同,而資料區段增加了4個位元組。
結論4:經過初始化的靜態變數儲存在資料區段中
繼續:
int main()
{
int i_data = 1;
return 1;
}
編譯:
可以發現,BSS段和和資料區段相同,而文本段增加了16個位元組。局部變數會在執行的時候在堆棧段中產生,函數執行完畢後釋放。
結論5:函數內部聲明的局部變數儲存在堆棧段中
繼續:
const int g_data = 1;
int main()
{
return 1;
}
編譯:
把全域變數定義為“const”後,也許你會感到奇怪,怎麼BSS段和資料區段都沒有發生變化,而文本段卻增加了4個位元組。
結論6:const修飾的全域變數儲存在文本段中
那麼,const的局部變數?
繼續:
int main()
{
const int i_data = 1;
return 1;
}
編譯:
結論7:const修飾的局部變數儲存在堆棧段中
繼續:
char *pstr = "";
int main()
{
return 1;
}
編譯:
在做一下更改:
char *pstr = "123456789";
int main()
{
return 1;
}
編譯:
可以發現,前後資料區段和BSS段大小均未發生變化,而文本段增加了9個位元組。
結論8:字串常量儲存在文本段中
1.1.3 結論
1、 經過初始化的全域變數和靜態變數儲存在資料區段中。
2、 未經初始化的全域變數和靜態變數儲存在BSS段。
3、 函數內部聲明的局部變數儲存在堆棧段中。
4、 const修飾的全域變數儲存在文本段中,const修飾的局部變數儲存在堆棧段中。
5、 字串常量儲存在文本段中。
1.1.4 擴充閱讀
《C專家編程》第6章——詳細介紹各個段的作用。