C語言extern關鍵字
extern,外面的、外來的意思。那它有什麼作用呢?舉個例子:假設你在大街上看到一個黑皮膚綠眼睛紅頭髮的美女(外星人?)或者帥哥。你的第一反應就是這人不是國產的。extern 就相當於他們的這些區別於中國人的特性。
extern 可以置於變數或者函數前,以標示變數或者函數的定義在別的檔案中,下面的代碼用到的這些變數或函數是外來的,不是本檔案定義的,提示編譯器遇到此變數和函數時在其他模組中尋找其定義。就好比在本檔案中給這些外來的變數或函數帶了頂帽子,告訴本檔案中所有代碼,這些傢伙不是本地人。
extern 修飾的變數或函數的三種形式:
1. extern修飾變數的聲明。舉例來說,如果檔案a.c需要引用b.c中變數int v,就可以在a.c中聲明extern int v,然後就可以引用變數v.這裡需要注意的是,被引用的變數v的連結屬性必須是外連結(external)的,也就是說a.c要引用到v,不只是取決於在a.c中聲明extern int v,還取決於變數v本身是能夠被引用到的。這涉及到c語言的另外一個話題--變數的範圍。能夠被其他模組以extern修飾符引用到的變數通常是全域變數。還有很重要的一點是,extern int v可以放在a.c中的任何地方,比如你可以在a.c中的函數fun定義的開頭處聲明extern int v,然後就可以引用到變數v了,只不過這樣只能在函數fun範圍中引用v罷了,這還是變數範圍的問題。對於這一點來說,很多人使用的時候都心存顧慮。好像extern聲明只能用於檔案範圍似的。
2. extern修飾函式宣告。從本質上來講,變數和函數沒有區別。函數名是指向函數二進位塊開頭處的指標。如果檔案a.c需要引用b.c中的函數,比如在b.c中原型是int fun(int mu),那麼就可以在a.c中聲明extern int fun(int mu),然後就能使用fun來做任何事情。就像變數的聲明一樣,extern int fun(int mu)可以放在a.c中任何地方,而不一定非要放在a.c的檔案範圍的範圍中。 對其他模組中函數的引用,最常用的方法是包含這些函式宣告的標頭檔。使用extern和包含標頭檔來引用函數有什麼區別呢?extern的引用方式比包含標頭檔要簡潔得多!extern的使用方法是直接了當的,想引用哪個函數就用extern聲明哪個函數。這大概是KISS原則的一種體現吧!這樣做的一個明顯的好處是,會加速程式的編譯(確切的說是預先處理)的過程,節省時間。在大型C程式編譯過程中,這種差異是非常明顯的。
3. 此外,extern修飾符可用於指示C或者C++函數的調用規範。比如在C++中調用C庫函數,就需要在C++程式中用extern "C"聲明要引用的函數。這是給連結器用的,告訴連結器在連結的時候用C函數規範來連結。主要原因是C++和C程式編譯完成後在目標代碼中命名規則不同。
下面依次來說幾個例子:
1.在同一個檔案內聲明的外部變數
#include <stdio.h>int max(int x,int y); //函數提前聲明int main(int argc,char *argv[ ] ){int result;extern int X; //外部變數聲明extern int Y;result = max(X,Y);printf("the max value is %dn",result);return 0;}int X = 10; //定義外部變數int Y = 20;int max(int x, int y){return (x>y ? x : y);}
這種用法基本上是畫蛇添足,直接就過吧
2.在不同檔案中聲明的外部變數
假設a.c的內容如下:
#include <stdio.h>extern int a;//外部變數提前聲明extern int exe(int x); //外部函數提前聲明int main(int argc, char *agrv[]){printf("%dn",exe(a));return 0;}
則b.c的內容如下:
#include <stdio.h>int BASE=2; //變數定義int a=10;int exe(int x){int i;int ret=1;for(i=0;i<x;i++){ret*=BASE;}return ret;}
在b.c檔案中定義a=10和exe函數,在a.c中引用a時,需要用extern關鍵字聲明其為外部變數,同樣的,在a.c中引用exe函數時也需要用extern關鍵字聲明其為外部函數,否則編譯會找不到該變數。
對於多個檔案的工程,可以採用這種方法來操作。實際工程中,對於模組化的程式檔案,在其檔案中可以預先留好外部變數的介面,也就是只採用extern聲明變數,不定義變數,也通常在模組程式的標頭檔中聲明,在使用該模組時,只需要在使用時定義一下即可,如上述a.c檔案,做好相應的函數介面,留好需要改變a值的聲明,在需要使用該模組時,只需要在調用的檔案中定義具體的值即可。
引用外部變數和通過函數形參值傳遞變數的區別:用extern引用外部變數,可以在引用的模組內修改其值,而形參值傳遞的變數則不能修改其值,除非是地址傳遞。因此,如果多個檔案同時對需要應用的的變數進行同時操作,可能會修改該變數,類似於形參的地址傳遞,從而影響其他模組的使用,因此,要謹慎使用。
(1) extern 變數名
在任何函數體外聲明或定義變數時,不加extern可能是定義也可能是聲明,編譯器選擇初始化的那個(最多一個地方對他進行了初始化),如果沒有初始化則任選其中一個作為定義,其他為聲明,但是加extern肯定是聲明; 如果不想讓其它源檔案連結到,則需要使用static關鍵字;在函數體內聲明(注意是聲明,在函數體內部不能定義外部變數)使用其他源檔案中定義的變數時,必須使用extern關鍵字,因為在函數體內預設為局部變數。
(2) extern 函數
函數預設是外部的(在函數體內或函數體外聲明一個外部函數,extern關鍵字均可省略),如果不想讓其它源檔案連結到,在函數前static關鍵字雖然在很多情況下extern關鍵字是可省的,但是為了提高程式的可讀性,還是加上它比較好.
待續。。。。