auto、register、static、extern等存儲類修飾符的區別 - [C/C++編程 ]
版權聲明 :轉載時請以超鏈接形式標明文章原始出處和作者信息及本聲明
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具有無鏈接,靜態生存週期;
}
From : http://kimva.blogbus.com/logs/19329180.html