C語言與C++中static,extern的用法及區別總結

在C語言中:

隱藏

  很多人經常會忘了這一條。其實這個作用很常用也很重要。
  當我們同時編譯多個文件時,所有未加static前綴的全局變量和函數都具有全局可見性。
  爲理解這句話,我舉例來說明。我們要同時編譯兩個源文件,一個是a.c,另一個是main.c。
  

char a = 'A'; // global variable
void msg() 
{
    printf("Hello\n"); 
}
int main(void)
{    
    extern char a;    
    printf("%c ", a);
    (void)msg();
    return 0;
}

程序的運行結果是:
A Hello

  爲什麼在a.c中定義的全局變量a和函數msg能在main.c中使用?
  前面說過,所有未加static前綴的全局變量和函數都具有全局可見性,其它的源文件也能訪問。 
  此例中,a是全局變量,msg是函數,並且都沒有加static前綴,因此對於另外的源文件main.c是可見的。
  如果加了static,就會對其它源文件隱藏。
  

static char a = 'A'; // global variable
static void msg() 
{
    printf("Hello\n"); 
}
int main(void)
{      
    printf("%c ", a);
    (void)msg();
    return 0;
}

  上面的程序會輸出什麼呢?
  答案是:報錯,找不到a與msg的定義。
  在a和msg的定義前加上static,main.c就看不到它們了。
  利用這一特性可以在不同的文件中定義同名函數和同名變量,而不必擔心命名衝突。

  static可以用作函數和變量的前綴,對於函數來講,static的作用僅限於隱藏。
  在上面的例子中,含有一個新的關鍵字——extern
  下面來講一下static和extern的區別:

extern

  extern告訴編譯器這個變量或函數在其他文檔裏已被定義了。

  看下面的例子:
  

static int i; //只在a文檔中用
int j;    //在工程裏用
static void init()         //只在a文檔中用
{
}
void callme()          //在工程中用
{
   static int sum;
}


extern int j;     //調用a文檔裏的
extern void callme();  //調用a文檔裏的
int main()
{
  ...
}

  上面的全局i變量和init()函數只能用在a.c文檔中,全局變量sum的作用域只在callme裏。變量j和函數callme()的全侷限擴充到整個工程文檔。所以能夠在下面的b.c中用extern關鍵字調用。extern告訴編譯器這個變量或函數在其他文檔裏已被定義了。

extern C

  extern的另外用法是當C和C++混合編程時假如c++調用的是c源文檔定義的函數或變量,那麼要加extern來告訴編譯器用c方式命名函數:
  

extern "C"  //在c++文檔裏調用c文檔中的變量
{
   int j;
   void callme();
}
int main()
{
   callme();
}

static法則:

  A、若全局變量僅在單個C文檔中訪問,則能夠將這個變量修改爲靜態全局變量,以降低模塊間的耦合度;
  B、若全局變量僅由單個函數訪問,則能夠將這個變量改爲該函數的靜態局部變量,以降低模塊間的耦合度;
  C、設計和使用訪問動態全局變量、靜態全局變量、靜態局部變量的函數時,需要考慮重入問題;

變量

1.變量定義的一般形式

存儲類別數據類型變量表;

2.變量定義的作用

①規定了變量的取值範圍。
②規定了變量進行的運行操作。
③規定了變量的作用域。
④規定了變量的存儲方式。
⑤規定了變量佔用的存儲空間。

3.局部變量和全局變量

從作用域角度將變量分爲局部變量和全局變量。它們採取的存儲類別如下:

局部變量:

①自動變量,即動態局部變量(離開函數,值就消失)。
②靜態局部變量(離開函數,值仍保留)。
③寄存器變量(離開函數,值就消失)。
④形式參數可以定義爲自動變量或寄存器變量。

全局變量:

①靜態外部變量(只限本程序文件使用)。
②外部變量(即非靜態的外部變量,允許其它程序文件引用)。

動態存儲和靜態存儲

  從變量存在時間可將變量存儲分爲動態存儲和靜態存儲。
  靜態存儲是在整個程序運行時都存在,而動態存儲則是在調用函數時臨時分配存儲單元。

動態存儲:

①自動變量(函數內有效)。
②寄存器變量(函數內有效)。
③形式參數。

靜態存儲:

①靜態局部變量(函數內有效)。
②靜態外部變量(本程序文件內有效)。
③外部變量(整個程序可引用)。

靜態存儲區和動態存儲區

  從變量值存放的位置可將變量存儲區分爲靜態存儲區和動態存儲區:

內存中靜態存儲區:

①靜態局部變量。
②靜態外部變量。
③外部變量(可被同一程序其它文件引用)。

內存中動態存儲區:自動變量和形式參數。

CPU中的寄存器:寄存器變量。

全局變量

  全局變量有外部、靜態兩種存儲方式。

外部全局變量

  全局變量一般用外部存儲方式存儲,用保留字extern加以定義。此時,變量的作用域是構成整個程序的所有程序文件,也就是定義的外部變量可供其它程序文件使用。
  使用這樣的全局變量一定要非常慎重,一旦產生錯誤,將波及整個程序。

靜態全局變量

  如果希望全局變量僅限於本程序文件使用,而其它程序文件中不能引用,這時必須將其存儲方式定義爲靜態存儲方式,用保留字static加以定義。此時稱爲靜態外部變量。
例如,在文件filel.c中,如果作這樣的定義:

static int a:

  則變量a的作用域被縮小至本程序文件filel1.c,文件file2.c中不能引用。
  值得注意的是對全局變量加static,定義爲靜態存儲方式,並不意味着是靜態存儲;而不加static,是動態存儲。
  兩種形式的全局變量(外部變量)都是靜態存儲方式,都是編譯時分配存儲空間,但作用域不同。使用靜態外部變量,有利於隔離錯誤,有利於模塊化程序設計。

全局變量的缺省存儲方式是外部存儲方式。

  前面章節中的程序沒有見到變量的存儲類別定義,實際上採用變量的缺省存儲方式。對局部變量採用auto方式,對全局變量採用extern方式。這也是至今爲止,我們在程序中沒有見到auto、extern等的原因。
至此,我們對變量的存儲類別及數據類型進行了全面討論,在此作個小結。

局部靜態變量

  在C/C++中, 局部變量按照存儲形式可分爲三種auto, static, register。其中register不常用到
  下面主要說說auto和static的區別。

  1. 存儲空間分配和生存週期不同

auto類型局部變量就是普通的局部變量(不加修飾的局部變量默認爲該類型)。該類型局部變量存儲在棧上,在動態存儲區,生命週期僅限於定義它的函數,函數結束,它就自動釋放。static類型局部變量存儲在靜態存儲區,在程序整個運行期間都不釋放。兩者之間的作用域相同,但生存期不同。
  2. static局部變量在所處模塊在初次運行時進行初始化工作,且只操作一次。
  3. 對於局部靜態變量,如果不賦初值,編譯期會自動賦初值0或空字符,而auto類型的初值是不確定的

  對於C++中的class對象例外,class的對象實例如果不初始化,則會自動調用默認構造函數,不管是否是static類型
  特點: static局部變量的”記憶性”與生存期的”全局性”

外部靜態變量/函數

  
  在C語言中 static有了第二種含義:
  用來表示不能被其它文件訪問的全局變量和函數。
  但爲了限制全局變量/函數的作用域, 函數或變量前加static使得函數成爲靜態函數。
  但此處“static”的含義不是指存儲方式,而是指對函數的作用域僅侷限於本文件(所以又稱內部函 數)。
  注意此時, 對於外部(全局)變量, 不論是否有static限制, 它的存儲區域都是在靜態存儲區,生存期都是全局的. 此時的static只是起作用域限制作用, 限定作用域在本模塊(文件)內部.
  使用內部函數的好處是:不同的人編寫不同的函數時,不用擔心自己定義的函數,是否會與其它文件中的函數同名。

靜態數據成員/成員函數

前兩種C和C++都有,這種僅在C++中有,下面作以下介紹:
  C+ +重用了這個關鍵字,並賦予它與前面不同的第三種含義:
  表示屬於一個類而不是屬於此類的任何特定對象的變量和函數.

  這是與普通成員函數的最大區別,也是其應用所在。
  比如在對某一個類的對象進行計數時, 計數生成多少個類的實例,就可以用到靜態數據成員。
  在這裏面, static既不是限定作用域的, 也不是擴展生存期的作用, 而是指示變量/函數在此類中的唯一性. 這也是”屬於一個類而不是屬於此類的任何特定對象的變量和函數”的含義.。
  因爲它是對整個類來說是唯一的,因此不可能屬於某一個實例對象的.
  針對靜態數據成員而言, 成員函數不管是否是static, 在內存中只有一個副本, 普通成員函數調用時, 需要傳入this指針, static成員函數調用時, 沒有this指針。
  
  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章