extern和static關鍵字

2022-05-28 10:33:15 字數 2562 閱讀 8314

在上一節我們把兩個程式檔案放在一起編譯鏈結,main.c用到的函式push、 pop和is_empty由stack.c提供,其實有一點小問題,我們用-wall選項編譯main.c可以看到:

gcc -c main.c -wall

main.c: in function 『main』:

main.c:

8: warning: implicit

declaration of function 『push』

main.c:

12: warning: implicit

declaration of function 『is_empty』

main.c:

13: warning: implicit declaration of function 『pop』

由於編譯器在處理函式呼叫**時沒有找到函式原型,只好根據函式呼叫**做隱式宣告,把這三個函式宣告為:

int push(char

);int pop(void

);int is_empty(void);

為什麼編譯器在處理函式呼叫**時需要有函式原型?因為必須知道引數的型別和個數以及返回值的型別才知道生成什麼樣的指令。為什麼隱式宣告靠不住呢?因為隱式宣告是從函式呼叫**推導而來的,而事實上函式定義的形參型別可能跟函式呼叫**傳的實參型別並不一致,如果函式定義帶有可變引數(例如printf),那麼從函式呼叫**也看不出來這個函式帶有可變引數,另外,從函式呼叫**也看不出來返回值應該是什麼型別,所以隱式宣告只能規定返回值都是int型的。

現在我們在main.c中宣告這幾個函式的原型:

/*

main.c

*/#include

extern

void push(char

);extern

char pop(void

);extern

int is_empty(void

);int main(void

)

這樣編譯器就不會報警告了。在這裡extern關鍵字表示這個識別符號具有external linkage。

push這個識別符號具有external linkage指的是:如果把main.c和stack.c鏈結在一起,如果push在main.c和stack.c中都有宣告(在stack.c中的宣告同時也是定義),那麼這些宣告指的是同乙個函式,鏈結之後是同乙個global符號,代表同乙個位址。函式宣告中的extern也可以省略不寫,不寫extern的函式宣告也表示這個函式具有external linkage。

如果用static關鍵字修飾乙個函式宣告,則表示該識別符號具有internal linkage,例如有以下兩個程式檔案:

/*

foo.c

*/static

void foo(void

) {}

/*main.c

*/void foo(void

);int main(void)

gcc foo.c main.c

/tmp/ccrc2yjn.o: in function `main'

:main.c:(.text+0x12): undefined reference to `foo'

collect2: ld returned 1 exit status

雖然在foo.c中定義了函式foo,但這個函式只具有internal linkage,只有在foo.c中多次宣告才表示同乙個函式,而在main.c中宣告就不表示它了。如果把foo.c編譯成目標檔案,函式名foo在其中是乙個local的符號,不參與鏈結過程,所以在鏈結時, main.c中用到乙個externallinkage的foo函式,鏈結器卻找不到它的定義在哪兒,無法確定它的位址,也就無法做符號解析,只好報錯。 凡是被多次宣告的變數或函式,必須有且只有乙個宣告是定義,如果有多個定義,或者乙個定義都沒有,鏈結器就無法完成鏈結。

如果想在乙個檔案中訪問另乙個檔案中的變數,則可以使用extern關鍵字宣告:

/*

main.c

*/#include

void push(char

);char pop(void

);int is_empty(void

);extern

inttop;

int main(void

)

變數top具有external linkage,它的儲存空間是在stack.c中分配的,所以main.c中的變數宣告extern int top;不是變數定義,因為它不分配儲存空間。以上函式和變數宣告也可以寫在main函式體裡面,使所宣告的識別符號具有塊作用域:

int main(void

)

注意,變數宣告和函式宣告有一點不同,函式宣告的extern可寫可不寫,而變數宣告如果不寫extern意思就完全變了,如果上面的例子不寫extern就表示在main函式中定義乙個區域性變數top。另外要注意, stack.c中的定義是int top = -1;,而main.c中的宣告不能加initializer,如果上面的例子寫成extern int top = -1;則編譯器會報錯。

關鍵字extern和static

關鍵字extern和static都能修飾函式和變數 extern 修飾函式 extern可完整的宣告函式以及定義函式,但是預設省略,意思是外部外部函式,均為全域性變數 修飾變數 extern不可定義變數。切記 如果宣告和定義都採用extern修飾 如 extern int a 則程式中就不存在 a ...

static和extern關鍵字介紹

學習中,發現遇到static和extern 尤其是extern 還是不能較系統地理清具體作用。於是寫下此篇部落格整理一下這兩個關鍵字。static,用static修飾的變數被稱為靜態變數,存在於靜態儲存空間。static一般有兩種用法,修飾全域性變數 函式 和修飾區域性變數。修飾全域性變數時 若初始...

學習筆記 關鍵字static 和 extern

static 主要修飾變數和修飾函式 靜態變數 儲存在靜態區 全域性區 靜態區域性變數 靜態區域性變數屬於靜態儲存方式,它具有以下特點 1 靜態區域性變數在函式內定義 它的生存期為整個源程式,但是其作用域仍與自動變數相同,只能在定義該變數的函式內使用該變數。退出該函式後,儘管該變數還繼續存在,但不能...