自: http://kimva.blogbus.com/logs/19329180.html
一、標識符的連結
(linkage)
(1)外部連結
表示在整個程式中(多個程式檔案)是相同的函數或對象。常見的有,在函數體外聲明的extern變數。
(2)內部連結
表示只在當前程式檔案中是相同的函數或對象。其它程式檔案不能對其進行訪問。常見的有,在函數體外聲明的static變數。
(3)無連結
一般聲明在函數內部的auto、register變數、還有函數的參數,都是無連結。它的範圍是函數內部。
二、對象的生存周期
(lifetime)
(1)靜態生存周期
具有靜態生存周期的所有對象,都是在程式開始執行之前
就被事先建立和初始化。它們的壽命覆蓋整個程式的執行過程。如在函數內定義了一個static變數,那第一次調用該函數後,該變數的值將會被保留,當第二次被調用時,該變數的值還是第一次調用結束時的值。
(2)自動生存周期
自動生存周期的對象的壽命由“對象定義所處在的大括弧{}”決定。每次程式執行流進入一個語句塊,此語句塊自動生存周期的對象就會被建立一個新執行個體,同時被初始化。
三、儲存類修飾符
(1)auto
auto修飾符只能用在函數內的對象聲明。聲明中有auto修飾符的對象具有自動生存周期。
在ANSI C中,函數內的對象聲明在預設情況下有自動生存周期,所以在函數內聲明時auto可省略。
(2)register
當聲明對象有自動生存周期時,可以使用register修飾符。因此,register也只能用在函數內的聲明中。
此關鍵字告訴編譯器:此對象的存取應該盡量快,最好儲存在CPU的寄存器中。然而,編譯器不見得會這麼做。
另外要注意的是,當一個對象聲明為register,就不可使用地址運算子&了,因為它有可能被放到寄存器中。
(3)static
函數標識符如果被聲明為static,就具有靜態生命週期。
如果是定義在函數外,那麼該對象具有內部連結,其它程式檔案不能對其訪問。
如果是定義在函數內,那麼該對象具有無連結,函數外不能對其訪問。
注意:static變數初始化時,只能用常量。
(4)extern
如果聲明在函數外,那麼該對象具有外部連結,能夠在其它程式檔案使用。但要注意它有可能會被函數內定義的重名的變數所隱藏起來。
如果聲明在函數內,該對象具有何種連結取決於當前程式檔案中定義在函數外的相同名字的對象。如果在函數外也定義了一下相同名字的static對象,則該函數內的對象具有無連結,否則具有外部連結。
extern的對象都具有靜態生命週期。
使用extern時,注意不能重複定義,否則編譯報錯,如:
程式檔案一:
extern int a = 10; //編譯警告,extern的變數最好不要初始化
程式檔案二:
extern int a = 20; //重複定義,應改為extern int a;
一般最好這樣,如果需要初始化,可把extern修飾符去掉(但也不要重複定義),另外如果其它程式檔案也需要用到該變數,可用extern來聲明該變數。這樣會比較清晰。
(5)缺
省修飾符
函數內,與auto相同;
函數外,與extern相同;
|
|
linkage |
lifetime |
| auto |
函數內 |
no linkage |
自動 |
| 函數外 |
文法錯 |
文法錯 |
| register |
函數內 |
no linkage |
自動 |
| 函數外 |
文法錯 |
文法錯 |
| 預設 |
函數內 |
no linkage |
自動 |
| 函數外 |
external linkage |
靜態 |
| static |
函數內 |
no linkage |
靜態 |
| 函數外 |
internal linkage |
靜態 |
| extern |
函數內 |
與它在函數外所聲明的一致 |
靜態 |
| 函數外 |
external linkage |
靜態 |
例子:
int func1(void); //func1具有外部連結;
int a = 10; //a具有外部連結,靜態生存周期;
extern int b = 1; //b具有外部連結,靜態生存周期。但編譯會有警告extern變數不應初始化,同時也要注意是否會重複定義;
static int c; //c具有內部連結,靜態生存周期;
static int e; //e具有內部連結,靜態生存周期;
static void func2(int d){ //func2具有內部連結;參數d具有無連結,自動生存周期;
extern int a; //a與上面的a一樣(同一變數),具有外部連結,靜態生存周期。注意這裡的不會被預設初始為0,它只是個聲明;
int b = 2; //b具有無連結,自動生存同期。並且將上面聲明的b隱藏起來;
extern int c; //c與上面的c一樣,維持內部連結,靜態生存周期。注意這裡的不會被預設初始為0,它只是個聲明;
//如果去掉了extern修飾符,就跟b類似了,無連結,自動生存周期,把上面聲明的c隱藏起來;
static int e; //e具有無連結,靜態生存周期。並且將上面聲明的e隱藏起來;初始化值為0;
static int f; //f具有無連結,靜態生存周期;
}