C語言內存分布
典型的C語言程序內存表示分區共有5個部分:
- 正文段 Text segment
- 已初始化數據段(數據段)Initialized data segment
- 未初始化數據段(bss)Uninitialized data segment
- 堆 Stack
- 棧 Heap
具體分布圖
各個分區的作用
- 正文段
- CPU執行的機器指令部分
- 通常可共享
- 常常是只讀的
- 已初始化數據段(數據段)
- 包含程序中需明確賦初始值的變量
- 保存已經初始化的全局變量
- 未初始化數據段(BSS)
- 在程序開始執行之前,內核將此段中的數據初始化為0或空指針
- 保存未初始化的全局變量(注意:即使是賦值為0也是未初始化!)
- 棧
- 存儲自動變量(如函數形參)及每次函數調用所需保存的信息
- 每次函數調用時,存放其返回地址及調用者的環境信息(如某些機器寄存器的值)
- 為最近被調用的函數分配自動變量和臨時變量的存儲空間
- 堆
- 動態存儲分配
初始化?
上面提到,對全局變量來說,如果是賦值為0仍是未初始化。下面給出實際實驗結果:
示例代碼1
#include <stdio.h>
int a;
int main(int argc, char const *argv[])
{
printf("hello\n");
return 0;
}
編譯后查看內存分布:
示例代碼2
#include <stdio.h>
int a = 0;
int main(int argc, char const *argv[])
{
printf("hello\n");
return 0;
}
編譯后查看內存分布:
可以看到,各個存儲區域數值沒有變化。
示例代碼3
#include <stdio.h>
int a = 1;
int main(int argc, char const *argv[])
{
printf("hello\n");
return 0;
}
編譯后查看內存分布:
可以看到,對全局變量進行真正的初始化之后,bss少了4個字節,data段多出了4個字節。
關於static的問題
示例代碼4
先看看相對上一例子,多了一個局部變量之后的內存分布。
#include <stdio.h>
int a = 1;
int main(int argc, char const *argv[])
{
int b;
printf("hello\n");
return 0;
}
編譯后查看內存分布:
可以看到,內存分布是沒有變化的,局部變量b
會在棧上分配到內存。
示例代碼5
如果把b
定義成static
呢?
#include <stdio.h>
int a = 1;
int main(int argc, char const *argv[])
{
static int b;
printf("hello\n");
return 0;
}
編譯后查看內存分布:
可以看到,此時bss上多出了8個字節。
示例代碼6
如果給b
賦初始值0呢?
#include <stdio.h>
int a = 1;
int main(int argc, char const *argv[])
{
static int b = 0;
printf("hello\n");
return 0;
}
編譯后查看內存分布:
可以看到,跟上一個例子相比沒有變化,說明跟全局變量一樣,static變量賦值為0仍是未初始化。
示例代碼7
如果給b
賦初始值1呢?
#include <stdio.h>
int a = 1;
int main(int argc, char const *argv[])
{
static int b = 1;
printf("hello\n");
return 0;
}
編譯后查看內存分布:
可以看到,bss少了4個字節,而data多了4個字節,說明靜態變量和全局變量同理,初始化之后是存在data段中的。
關於static的用處
示例代碼8
#include <stdio.h>
int x = 4;
void incre() {
static int x = 1;
x *= x + 1;
printf("%d\n", x);
}
int main(int argc, char const *argv[])
{
int i;
for (i = 1; i < x; i++) {
incre();
}
return 0;
}
運行結果為:
可以看到,函數incre
中x
的作用域存在於其局部,但是卻在每次調用函數的時候沿用之前的值!這是因為static定義的變量是靜態變量,有着靜態存儲位置(變量存儲位置固定不動,若在代碼中已經初始化則存在於data段,否則存在於bss段),而不是存在於棧上,因此每次調用函數讀取到的變量的值都是靜態存儲區的值。
static的意義
-
全局靜態變量
- 不會被其它文件所訪問和修改
- 其它文件中可以使用相同名字的變量,不會發生沖突
-
局部靜態變量
- 可以用作計數器,每次函數調用的時候可以進行計數
-
靜態函數
- 其它文件中可以定義相同名字的函數,不會發生沖突
- 靜態函數不能被其它文件所用
- 靜態函數會被分配在一個一直使用的存儲器,直到程序退出,避免了調用函數時進棧出棧,提升運行速度
參考書目
- 《Unix環境高級編程》(中文第三版)
- 《C primer plus》(中文第五版)