天天看點

C語言與C++中static,extern的用法及差別總結在C語言中:隐藏externextern Cstatic法則:變量動态存儲和靜态存儲靜态存儲區和動态存儲區外部靜态變量/函數靜态資料成員/成員函數

在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 ;
}
           

程式的運作結果是:

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 ;
}
           

  上面的程式會輸出什麼呢?

  答案是:報錯,找不到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指針。