C語言儲存型別
首先要來理解一下可執行檔案載入進記憶體後形成的程序在記憶體中的結構,如下圖:
程式碼區:存放CPU執行的機器指令,程式碼區是可共享,並且是隻讀的。
資料區:存放已初始化的全域性變數、靜態變數(全域性和區域性)、常量資料。
BBS區:存放的是未初始化的全域性變數和靜態變數。
棧區:由編譯器自動分配釋放,存放函式的引數值、返回值和區域性變數,在程式執行過程中實時分配和釋放,棧區由作業系統自動管理,無須程式設計師手動管理。
堆區:堆是由malloc()函式分配的記憶體塊,使用free()函式來釋放記憶體,堆的申請釋放工作由程式設計師控制,容易產生記憶體洩漏。
c語言中的儲存型別有auto, extern, register, static 這四種,儲存型別說明了該變數要在程序的哪一個段中分配記憶體空間,可以為變數分配記憶體儲存空間的有資料區、BBS區、棧區、堆區。下面來一一舉例看一下這幾個儲存型別:
1. auto儲存型別
auto只能用來標識區域性變數的儲存型別,對於區域性變數,auto是預設的儲存型別,不需要顯示的指定。因此,auto標識的變數儲存在棧區中。示例如下:
- #include <stdio.h>
- int main(void)
- {
- auto int i=1; //顯示指定變數的儲存型別
- int j=2;
- printf("i=%d\tj=%d\n",i,j);
- return 0;
- }
2. extern儲存型別
extern用來宣告在當前檔案中引用在當前專案中的其它檔案中定義的全域性變數。如果全域性變數未被初始化,那麼將被存在BBS區中,且在編譯時,自動將其值賦值為0,如果已經被初始化,那麼就被存在資料區中。全域性變數,不管是否被初始化,其生命週期都是整個程式執行過程中,為了節省記憶體空間,在當前檔案中使用extern來宣告其它檔案中定義的全域性變數時,就不會再為其分配記憶體空間。
示例如下:
- #include <stdio.h>
- int i=5; //定義全域性變數,並初始化
- void test(void)
- {
- printf("in subfunction i=%d\n",i);
- }
- #include <stdio.h>
- extern i; //宣告引用全域性變數i
- int main(void)
- {
- printf("in main i=%d\n",i);
- test();
- return 0;
- }
-
$ gcc -o test test.c file.c #編譯連線
- $ ./test #執行
- 結果:
- in main i=5
- in subfunction i=5
3. register儲存型別
宣告為register的變數在由記憶體調入到CPU暫存器後,則常駐在CPU的暫存器中,因此訪問register變數將在很大程度上提高效率,因為省去了變數由記憶體調入到暫存器過程中的好幾個指令週期。如下示例:
- #include <stdio.h>
- int main(void)
- {
- registerint i,sum=0;
- for(i=0;i<10;i++)
- sum=sum+1;
- printf("%d\n",sum);
- return 0;
- }
4. static儲存型別
被宣告為靜態型別的變數,無論是全域性的還是區域性的,都儲存在資料區中,其生命週期為整個程式,如果是靜態區域性變數,其作用域為一對{}內,如果是靜態全域性變數,其作用域為當前檔案。靜態變數如果沒有被初始化,則自動初始化為0。靜態變數只能夠初始化一次。示例如下:
- #include <stdio.h>
- int sum(int a)
- {
- auto int c=0;
- staticint b=5;
- c++;
- b++;
- printf("a=%d,\tc=%d,\tb=%d\t",a,c,b);
- return (a+b+c);
- }
- int main()
- {
- int i;
- int a=2;
- for(i=0;i<5;i++)
- printf("sum(a)=%d\n",sum(a));
- return 0;
- }
- $ gcc -o test test.c
- $ ./test
- a=2, c=1, b=6 sum(a)=9
- a=2, c=1, b=7 sum(a)=10
- a=2, c=1, b=8 sum(a)=11
- a=2, c=1, b=9 sum(a)=12
- a=2, c=1, b=10 sum(a)=13
6. 字串常量
字串常量儲存在資料區中,其生存期為整個程式執行時間,但作用域為當前檔案,示例如下:
- #include <stdio.h>
- char *a="hello";
- void test()
- {
- char *c="hello";
- if(a==c)
- printf("yes,a==c\n");
- else
- printf("no,a!=c\n");
- }
- int main()
- {
- char *b="hello";
- char *d="hello2";
- if(a==b)
- printf("yes,a==b\n");
- else
- printf("no,a!=b\n");
- test();
- if(a==d)
- printf("yes,a==d\n");
- else
- printf("no,a!=d\n");
- return 0;
- }
- $ gcc -o test test.c
- $ ./test
- yes,a==b
- yes,a==c
- no,a!=d
總結如下表: