extern 標頭檔案

2021-06-16 09:19:12 字數 2853 閱讀 7152

很多情況下,程式設計師可能突然產生這樣的問題:為什麼非得在檔案的首位置#include "... .h"? 我include原始檔行不行。

//

single.cpp

#ifndef __single__cpp_

#define __single__cpp_

#include void fun()

#endif/*__single__cpp_*/

//

main.cpp

#include"

single.cpp

"void main()

vc2008下編譯,出現如下問題:

為什麼會出現這樣的情況呢?

其實c語言的編譯方式是分離式的,分為兩步(簡單起見我們假設只有乙個生成目標):

1、將乙個或多個原始檔編譯成可重定位的目標檔案,其中每個檔案是分別編譯的。

2、將1步生成的可重定位目標檔案鏈結成乙個可執行目標檔案或者共享目標檔案。

因此,假設foo1.c中用include指令包含了foo2.c,foo2.c中定義了函式function且沒有用static修飾。那麼經過預處理,foo1.c中也將包含function的定義。於是foo1.c生成的可重定位目標檔案(假設為foo1.o)和foo2.c(假設為foo2.o)都有function這個符號,這樣上面所說的第二步就會因為衝突而失敗。

事實上,在沒有標頭檔案可被包含的情況下(事實上初期,是最早最早的時候),我們可以採用如下的方式:

//

main.cpp

extern fun();

void main()

程式編譯執行,是我們想要的結果。其實這個就是乙個前置宣告。事實上,我們不加"extern"關鍵字,編譯也正常:

//

main.cpp

void fun();

void main()

這是因為:函式具有定義和宣告,定義的時候用extern,說明這個函式是可以被外部引用的,宣告的時候用extern說明這是乙個宣告。但由於函式的定義和宣告是有區別的,定義函式要有函式體,宣告函式沒有函式體,所以函式定義和宣告時都可以將extern省略掉,反正其他檔案也是知道這個函式是在其他地方定義的,所以不加extern也行。兩者如此不同,所以省略了extern也不會有問題。

我們再看變數的宣告和定義:

extern

int a; //

宣告乙個全域性變數a

int a; //

定義乙個全域性變數a

extern

int a =0 ; //

定義乙個全域性變數a 並給初值。

int a =0; //

定義乙個全域性變數a,並給初值,

第四個等於第三個,都是定義乙個可以被外部使用的全域性變數,並給初值。但是定義只能出現在一處。也就是說,不管是int a;還是extern int a=0;還是int a=0;都只能出現一次,而那個extern int a可以出現很多次。當你要引用乙個全域性變數的時候,你就要宣告,extern int a;這時候extern不能省略,因為省略了,就變成int a;這是乙個定義,不是宣告。

因此,訪問者模組時仍要對變數進行宣告,而這時候是必須要加"extern"關鍵字的。

這樣我們出現乙個問題?既然extern+前置宣告都能實現這些功能?為什麼還得將宣告放在標頭檔案中並被包含呢?我覺得下面這段話說得很清楚:

在c語言家族程式中,標頭檔案被大量使用。一般而言,每個c++/c程式通常由標頭檔案(header files)和定義檔案(definition files)組成。標頭檔案作為一種包含功能函式、資料介面宣告的載體檔案,用於儲存程式的宣告(declaration),而定義檔案用於儲存程式的實現 (implementation)。

c++/c程式的標頭檔案以「.h」為字尾。以下是假設名稱為 graphics.h的標頭檔案:

#ifndef graphics_h (作用:防止graphics.h被重複引用)

#define graphics_h

#include.... (作用:引用標準庫的標頭檔案)

...#include... (作用:引用非標準庫的標頭檔案)

...void function1(...); (作用:全域性函式宣告)

...class box (作用:類結構宣告)

;#endif

從以上例子可以看出,標頭檔案一般由三部分內容組成:(1)標頭檔案開頭處的版權和版本宣告;(2)預處理塊;(3)函式和類結構宣告等。在標頭檔案中,用 ifndef/define/endif結構產生預處理塊,用 #include 格式來引用庫的標頭檔案。標頭檔案的這種結構,是利用c語言進行開發軟體所通常具備的,屬於公有知識。

一般在乙個應用開發體系中,功能的真正邏輯實現是以硬體層為基礎,在驅動程式、功能層程式以及使用者的應用程式中完成的。根據以上示例,可以發現標頭檔案的主要作用在於呼叫庫功能,對各個被呼叫函式給出乙個描述,其本身不包含程式的邏輯實現**,它只起描述性作用,告訴應用程式通過相應途徑尋找相應功能函式的真正邏輯實現**。使用者程式只需要按照標頭檔案中的介面宣告來呼叫庫功能,編譯器會從庫中提取相應的**。

從以上結構圖來看,標頭檔案是使用者應用程式和函式庫之間的橋梁和紐帶。在整個軟體中,標頭檔案不是最重要的部分,但它是c語言家族中不可缺少的組成部分。做乙個不算很恰當的比喻,標頭檔案就像是一本書中的目錄,讀者(使用者程式)通過目錄,可以很方便就查閱其需要的內容(函式庫)。在一本書中,目錄固然重要,但絕對不是一本書的核心的、最重要的部分。

你既然寫出了乙個模組並且要提供給其它模組使用的功能,你總不能讓其它模組去「猜」你模組的哪些介面吧。所以這時候乾脆再帶個索引一樣的標頭檔案。當然如果你只提供了索引不提供內容,則會發生編譯時沒問題,鏈結時出問題。

標頭檔案與extern

好吧,標頭檔案是幹嘛的?放心,這個簡單的問題確實把我難住了。用了多少年頭檔案,標頭檔案是幹嘛用的?第一,標頭檔案是給別人看得。第二,標頭檔案可以用來進行型別檢查,減少出錯。好吧,第二點我似懂非懂,所以只說第一點。再配合extern。他們倆在一起很萬惡的。真的哦!標頭檔案是給別人看的。不管是c還是c ...

對於C語言標頭檔案裡面extern的理解

如果想在乙個c檔案裡面引用另外乙個c檔案裡面的變數,怎!麼!辦?我們的做法是將變數在h檔案中宣告為ertern,然後在其他檔案中匯入這個h檔案。這裡需要注意的是,如果匯入了h檔案,那就不能宣告同名的變數了。另外,h檔案中的宣告變數必須是在別的檔案裡面已經宣告過的。這裡特別強調制!量!如上圖。左邊是h...

extern和標頭檔案在多檔案編譯過程中的作用

多檔案編譯中,extern 外來的 是連線這些檔案的關鍵。只要多個檔案處於乙個工程中 vs 或者使用gcc一起編譯 linux,如gccfile1.c file2.c otest extern可以將本檔案中定義的變數或者函式的作用域至其他檔案,當然這些變數和函式必須是全域性的。編譯 gcc file...