C/C++中static和extern小結

static和extern是C/C++中和函數的聲明有關的兩個關鍵字,特別是涉及到全局變量時,所以做此總結。


1. static關鍵字

1.1 函數和變量聲明(C/C++)

  1. static全局變量:

    當聲明一個static全局變量,則表示靜態全局變量,和其他變量一樣,存放在.data(初始化了)或者.bss(未初始化)內,但只在定義它的源文件中有效,其餘文件無法訪問它

  2. static局部變量:

    具有以下特點:

    • 函數中聲明一個static局部變量,不分配在堆或者棧上,也分配在.data(不分配在.bss)上

    • 雖然是局部變量,整個進程生命週期都存在,不被釋放。

    • 雖然一直存在,其餘函數不能訪問,其餘源文件更不能

    • 會被自動初始化(所以不在.bss)上(普通局部變量不會,普通全局變量會自動初始化)

    • 更進一步,每次調用這個變量時,其初始值都是上一次調用時修改的結果

  3. static函數:

    類似面向對象中private封裝,其只能被所定義的源文件調用,不能再其他源文件中調用(即使包含頭文件。。。。)

1.2 類成員的static(C++)

  1. 所有對象共有數據成員或者成員函數,類的靜態成員,在類創建時就存在(不需要對象)。

  2. static關鍵字只能用於類內部的聲明,不能用於類外部的定義。

  3. static成員函數沒有this形參(因爲不屬於某個對象),可以直接訪問static數據成員,不能直接使用非static成員。

  4. static成員函數不能聲明爲const,因爲const成員函數真正的含義是不修改該成員函數所屬的對象,而static成員函數不屬於任何對象。

  5. 同上,static成員函數不能聲明爲虛函數!

  6. static不是對象的組成部分,只是類的組成部分

2. extern關鍵字

  1. extern關鍵字常用於頭文件中變量的聲明,表示這個變量的定義在其他文件中的全局變量,提示編譯器當遇到這個變量時,在其他文件中查找。

  2. 現代編譯器一般採用按文件編譯的方式,因此在編譯時,各個文件中定義的全局變量是互相不透明的。也就是說,在編譯時,全局變量的可見域限制在文件內部。

    • 編譯階段是對各個文件進行單獨編譯,所以不會出錯,鏈接階段則出現了衝突,因爲都是全局變量,變量名也一樣
    • 需要注意的是,此時兩個文件並沒有使用include包含,只是一同編譯。(如果使用include包含,則不需extern)
  3. 結合static來說,舉例說明:

a.cpp如下:

int i = 1;

b.cpp如下:

#include <iostream>
using namespace std;

extern int i;
int main() {
    int a = i + 1cout << a << endl;
    }   

編譯:

g++ -O0 -std=c++11 -o run ./a.cpp b.cpp
./run

結果:

2
  • 如果將b.cpp中extern去掉,則因爲i在a.cpp中已經定義爲了全局變量,當兩個文件編譯後進行鏈接時,會產生衝突,報錯如下:
/tmp/ccednFyK.o:(.data+0x0): multiple definition of `i'
  • 如果將a.cpp中變量i加上static,同樣出錯,因爲static限制了i只能在a.cpp中使用,報錯如下:
b.cpp:(.text+0xa): undefined reference to `i'



值得注意的是:

C++將聲明和定義分開就是爲了防止重複編譯導致大量不必要的開銷,所以採用了“一處定義,多處聲明”的策略,也就是頭文件中只包含聲明,將定義放在同名的代碼源文件中。

Essential C++中強調了const object和inline函數是“一次定義”的例外

  • inline函數因爲需要編譯器對其進行展開,所以需要編譯器在每個函數的調用點上都需要知悉函數的定義,所以常常將inline函數置於頭文件中。

  • const object因爲一出文件之外便不可見(const關鍵字的特性),所以需要頭文件中進行定義(因爲include頭文件,所以可以調用)

    • 如果希望在其他文件中調用(非include包含)const全局變量,需要在變量的定義時顯示聲明爲extern。這樣在其他文件中,通過extern可以調用這個全局const object。(其實,非const的普通全局變量默認就是extern的)。
// a.cpp
extern const int i = 1;
int j = 2;
const int k = 3;

// b.cpp
extern const int i;
extern int j;
extern const in k;
int num = i + 1;     // OK
int num = j + 1;     // OK
int num = k + 1;     // ERROR
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章