關於標頭檔案中定義的全域性變數的包含

2021-06-16 08:33:09 字數 2252 閱讀 3449

在標頭檔案中定義了乙個變數,若另乙個檔案包含此檔案則會再產生乙個相同變數的定義,在linux環境中編譯時會發生如

menu.o:(.sbss+0x0): multiple definition of `is_refresh_living_time_thread_created'

main.o:(.sbss+0x0): first defined here

的錯誤,要在包含該檔案的檔案中使用此變數應該宣告全域性變數「extern int is_refresh_living_time_thread_created」,或者叫作「通過extern關鍵字擴充套件全域性變數is_refresh_living_time_thread_created的作用範圍(即擴充套件到包含該檔案的檔案中)」;這和標頭檔案中的函式宣告不同,因為函式在標頭檔案中僅僅是宣告,宣告可以有多個,但是無論是函式還是變數定義都只能有乙個,否則就會發生重複定義的錯誤。

標頭檔案中變數如果沒有初始化就是宣告;初始化了就是定義,此時被包含之後會發生重複定義的錯誤。

並不是所有的變數都能用extern宣告,只有全域性變數並且沒有被static 宣告的變數才能宣告為extern. 所以如果你不想自己原始檔中全域性的變數被其他檔案引用,你就可以給變數加上static宣告.

很多初學者,對變數的定義和宣告分不請,只知道有這回事。下面對這兩個概念詳細說明下:

變數的定義:為變數分配儲存空間,同時指明變數的型別和名字。另外變數的初始化,就是在變數的定義出給出值。

變數的宣告:它主要向程式宣告變數的型別和名字。定義也是宣告(這是許多人搞不清楚的地方),那既然變數的定義就是宣告,為啥還要再多出來個變數的宣告這個概念,直接就用變數的定義不是就可以了?

其實不然,c++中有個關鍵字是用來宣告變數的,它是extern。它宣告乙個變數卻不定義它,即不在給它乙個儲存空間。

例如:int i;//定義也可以說是宣告

extern int i;//這就是單純的宣告

注意:在c++語言中,變數有且只能有一次定義,但是可以宣告多次,使用變數前必須定義或宣告。

這依然沒有說明這個變數宣告有什麼作用,下面就舉個例子說明變數宣告的作用

假設我們在檔案1.cpp中定義了乙個全域性變數bufsize,檔案1.cpp中當然可以訪問它,如果我想在另外乙個檔案2.cpp中訪問這個全域性變數,這時候需要在檔案2.cpp中宣告這個變數。

int bufsize;

extern int bufsize;

這說的是非const的全域性變數,如果是const的全域性變數,如果想要被其他檔案訪問,需要在定義的時候,加上extern關鍵字,表示它可以在其他檔案被宣告使用的,即可以被整個程式(乙個程式可能包括多個原始檔)訪問,否則的話,這個變數只能在它被定義的檔案裡面被訪問,其他檔案不能訪問。

extern const int bufsize=10;

extern const int bufsize;

這時候你也許會問,為什麼非const變數定義的時候為什麼沒有extern?

答:非const變數預設為extern。而const變數如果想要在其他檔案裡被訪問,必須顯示的指定它為extern。

看完這個你會對變數的宣告和定義有了個新的理解^-^

今天看c++ primer關於標頭檔案定義的一節,其中說到,標頭檔案應用於宣告而不是用於定義。其實,c++標準並沒有規定標頭檔案中不能定義 變數,只不過如果在標頭檔案中定義變數,而該標頭檔案又被多次包含的話,會造成變數的重新定義。

這裡還涉及到另乙個問題,需要提前說明,即使用預處理器避免多重包含。這裡的多重包含指的是同乙個檔案直接或者間接的包含乙個標頭檔案多次,例如a.h包含b.h,a.cpp同時包含a.h和b.h,a.cpp就兩次包含了b.h。但由於b.h中具有避免多重包含的措施,a.cpp中還是只包含了b.h一次。而包含的意思其實就是在預處理階段用被包含檔案的內容代替此包含語句。

回到標頭檔案定義變數的問題上,如果在標頭檔案中定義了變數,避免多重包含的措施只能避免該標頭檔案在同乙個編譯單元內被包含一次,在不同的編譯單元內還是會被多次包含的,這樣就造成了變數的重複定義。

但是也有例外,如果const物件在編譯時可以確定其值,可以將其放在標頭檔案中定義。這麼做是有原因的——const物件預設情況下是定義該變數的檔案的區域性變數,這樣即使此標頭檔案被多個包含,都不會在包含這些檔案中重複定義此變數,所有對於這個const物件的引用全都指向在標頭檔案中定義的物件。如果在const物件定義的時候宣告extern,const物件就變得和普通非const物件一樣,從而失去此特性(非const物件的預設屬性為extern)。

c++中的很多用法都不是標準c++規定的,但是由於各種原因,已經是約定俗成或是慣常用法,至於原因以及除此之外的其他用法完全可以不必深究,否則很容易鑽牛角尖!

關於標頭檔案中定義的全域性變數的包含

在標頭檔案中定義了乙個變數,若另乙個檔案包含此檔案則會再產生乙個相同變數的定義,在linux環境中編譯時會發生如下的錯誤。menu.o sbss 0x0 multiple definition of is refresh living time thread created main.o sbss ...

全域性變數在標頭檔案中「定義」

看著標題,定義上面加了乙個引號,這個得注意了。怎麼解釋呢,一般而言,變數只能定義在.c檔案中,宣告變數才在.h檔案中。下面就打破常規,把定義變數的語句放在.h檔案中,但是對實際而言,變數定義在標頭檔案中是表面上的。下面直接給出 有三個檔案a.h a.c main.c a.h裡面的 csharp vi...

標頭檔案中用static定義全域性變數的問題

cocos3.13前的版本中,一些全域性變數使用static 定義,研究了static定義全域性變數的優缺點。例如定義下面的標頭檔案 pragma once static int globle 0 static int image 省略 在其他原始檔中,引用cocos.h標頭檔案後,每個原始檔都會儲...