假設在test.h中定義了一個static bool g_test=false;
若test1.c和test2.c都包含test.h,則test1.c和test2.c分別產生兩份g_test,在test1.c 中置g_test=true,而test2.c中仍然為false並未改變!shit!!
一、c程式儲存空間布局
C程式一直由下列部分組成:
1)本文段——CPU執行的機器指令部分;一個程式只有一個副本;唯讀,防止程式由於意外事故而修改自身指令;
2)初始化資料區段(資料區段)——在程式中所有賦了初值的全域
變數
,存放在這裡。
3)非初始化資料區段(bss段)——在程式中沒有初始化的全域變數
;核心將此段初始化為0。
4)棧——增長方向:自頂向下增長;自動變數
以及每次函數調用時所需要儲存的資訊(返回地址;環境資訊)。
5)堆——動態儲存裝置分。
|-----------|
| |
|-----------|
| 棧 |
|-----------|
| | |
| |/ |
| |
| |
| /| |
| | |
|-----------|
| 堆 |
|-----------|
| 未初始化 |
|-----------|
| 初始化 |
|-----------|
| 本文段 |
|-----------|
二、 面向過程程式設計中的static
1. 全域靜態變數
在全域變數
之前加上關鍵字static
,全域變數
就被定義成為一個全域靜態變數
。
1)記憶體中的位置:靜態儲存區(靜態儲存區在整個程式運行期間都存在)
2)初始化:未經初始化的全域靜態變數
會被程式自動初始化為0(自動對象的值是任意的,除非他被顯示初始化)
3)範圍:全域靜態變數
在聲明他的
檔案
之外是不可見的。準確地講從定義之處開始到檔案
結尾。
看下面關於範圍的程式:
//teststatic1.c
void display();
extern int n;
int main()
{
n = 20;
printf("%dn",n);
display();
return 0;
}
//teststatic2.c
static
int n; //定義全域靜態變數
,自動初始化為0,僅在本檔案
中可見
void display()
{
n++;
printf("%dn",n);
}
檔案
分別編譯通過,但link的時候teststatic2.c
中的變數
n找不到定義,產生錯誤。
定義全域靜態變數
的好處:
<1>不會被其他檔案
所訪問,修改
<2>其他檔案
中可以使用相同名字的變數
,不會發生衝突。
2. 局部靜態變數
在局部變數
之前加上關鍵字static
,局部變數
就被定義成為一個局部靜態變數
。
1)記憶體中的位置:靜態儲存區
2)初始化:未經初始化的全域靜態變數
會被程式自動初始化為0(自動對象的值是任意的,除非他被顯示初始化)
3)範圍:範圍仍為局部範圍,當定義它的函數或者語句塊結束的時候,範圍隨之結束。
註:當static
用來修飾局部變數
的時候,它就改變了局部變數
的儲存位置,從原來的棧中存放改為靜
態儲存區。但是局部靜態變數
在離開範圍之後,並沒有被銷毀,而是仍然駐留在記憶體當中,直到程式結束,只不過我們不能再對他進行訪問。
當static
用來修飾全域變數
的時候,它就改變了全域變數
的範圍(在聲明他的檔案
之外是不可見的),但是沒有改變它的存放位置,還是在靜態儲存區中。
3. 靜態函數
在函數的傳回型別前加上關鍵字static
,函數就被定義成為靜態函數。
函數的定義和聲明預設情況下是extern的,但靜態函數只是在聲明他的檔案
當中可見,不能被其他檔案
所用。
例如:
//teststatic1.c
void display();
static
void staticdis();
int main()
{
display();
staticdis();
renturn 0;
}
//teststatic2.c
void display()
{
staticdis();
printf("display() has been called n");
}
static
void staticdis()
{
printf("staticDis() has been calledn");
}
檔案
分別編譯通過,但是串連的時候找不到函數staticdis()的定義,產生錯誤。
實際上編譯也未過,vc2003報告teststatic1.c中靜態函數staticdis已聲明但未定義 ;by imjacob
定義靜態函數的好處:
<1> 其他檔案
中可以定義相同名字的函數,不會發生衝突
<2> 靜態函數不能被其他檔案
所用。
儲存說明符auto,register,extern,static
,對應兩種儲存期:自動儲存期和靜態儲存期。
auto和register對應自動儲存期。具有自動儲存期的變數
在進入聲明該變數
的程式塊時被建立,它在該程式塊活動時存在,退出該程式塊時撤銷。
關鍵字extern和static
用來說明具有靜態儲存期的變數
和函數。用static
聲明的局部變數
具有靜態儲存持續期(static
storage duration),或靜態範圍(static
extent)。雖然他的值在函數調用之間保持有效,但是其名字的可視性仍限制在其局部域內。靜態局部對象在程式執行到該對象的聲明處時被首次初始化。
由於static
變數
的以上特性,可實現一些特定功能。
1. 統計次數功能
聲明函數的一個局部變數
,並設為static
類型,作為一個計數器,這樣函數每次被調用的時候就可以進行計數。這是統計函數被調用次數的最好的辦法,因為這個變數
是和函數息息相關的,而函數可能在多個不同的地方被調用,所以從調用者的角度來統計比較困難。代碼如下:
void count();
int main()
{
int i;
for (i = 1; i <= 3; i++)
count();
return 0;
}
void count()
{
static
num = 0;
num++;
printf(" I have been called %d",num,"timesn");
}
輸出結果為:
I have been called 1 times.
I have been called 2 times.
I have been called 3 times.
轉自:http://dream2fly.net/blog/?action=show&id=75