2010-05-24 57 views
2

我有2個cpp文件&一個頭文件,我已經包含在這兩個cpp文件中。它是這樣的:extern變量的問題

abc.h

extern uint32_t key; 

a.cpp

#include "abc.h" 
uint32_t key; 
int main 
{ 
............. 
} 

b.cpp

#include "abc.h" 

int main 
{ 
printf("Key: %.8x\n", key); 
............. 
} 

現在,當我編譯a.cpp,沒有錯誤。但是當我編譯b.cpp時,它給出錯誤 「未定義的引用'key'」。請幫助我在此代碼中找到問題。

+0

你能告訴我們你是如何編譯'b.cpp'嗎?你是否包含a.cpp作爲你的構建的一部分? – 2010-05-24 17:34:57

回答

9

要共享變量,你通常是這樣的:

// A.h 
extern int key; 
void show(); 

//a.cpp 
#include "a.h" 

int main() { 
    key = 1; 
    show(); 
}; 

// b.cpp 
#include "a.h" 
#include <iostream> 

int key; 

void show() { std::cout << "Key = " << key; } 

有幾個點來不在這裏。首先,你把extern聲明放在一個頭文件中,並將它包含在全部這些使用該變量的文件中。在一個且只有一個文件中定義變量(沒有extern)。只有一個文件應該包含一個名爲main的函數。

編輯:建立這個,你自己編譯每個文件,但你必須將鏈接這兩個文件放在一起。例如,使用gcc你可以這樣做:

gcc -c a.c 
gcc -c b.c 
gcc a.o b.o 

第一次編譯(但不鏈接)a.c.第二種方法與b.c相同。第三種方法實際上將兩者聯繫在一起並生成可執行的二進制映像(傳統上命名爲a.out,但是,例如,在Windows上,通常將其更改爲a.exe)。

+0

這與OP場景有何不同?你在b.cpp中定義了密鑰,他是在a.cpp中完成的......他的做法有什麼問題? – 2010-05-24 17:29:12

+3

這是從兩個源文件構建一個程序;看起來OP正試圖建立兩個程序。 – 2010-05-24 17:31:01

+0

@Mike:是的,我錯過了有兩條主線的事實。我們需要教授OP關於編譯... – 2010-05-24 17:38:11

1

我猜你正在收到鏈接錯誤?鏈接b時需要包含a.o,但如果在a和b中都有「main」,則不起作用。您需要製作聲明密鑰的c.cpp,並將c.o鏈接到a.exe和b.exe中。

3

問題正是錯誤信息所說的。 Abc.h 聲明瞭這個變量,但它不是定義爲它。 a.cpp中的行定義了它。也就是說,a.cp​​p是變量的物理存儲位置。在b.cpp中沒有這樣的行,所以當你嘗試編譯該程序時,鏈接器沒有爲該變量定義任何存儲空間。

如果您在頭文件中省略了「extern」說明符,那麼b.cpp將編譯得很好,但a.cpp可能會給出關於多個定義的錯誤。

當在一個程序中有多個源文件時,「extern」說明符扮演着更重要的角色。在這種情況下,它們可能都包含abc.h,但是如果沒有「extern」,每個編譯的目標文件都會有相同變量的獨立定義。鏈接器通常不知道該怎麼做,並且可能會抱怨,儘管我不認爲這是必要的。修正是使用「extern」,因此每個編譯的文件文件只有一個聲明。然後你選擇一個源文件來放置定義。你可能會把它放在abc.cpp中,因爲聲明在abc.h中。

2

您正在編譯兩個單獨的程序。不能從另一個引用變量。所述extern關鍵字是在同一可執行是的另一個對象文件從一個對象文件引用的符號。

1

從報頭文件中的行是一個聲明;它告訴編譯器該變量存在,但不爲其分配任何空間。當您從一個或多個源文件構建程序時,其中一個還必須包含定義

你的情況,你有a.cpp的定義,使包含編譯程序所需的一切。 b.cpp沒有定義,所以它將無法鏈接。

有兩種解決方案。將a.cpp中的定義複製到b.cpp,或將其移至第三個源文件,並在構建兩個程序時將其包含在源列表中。

0

a.cppb.cpp都定義了main()函數,並且您只允許爲每個程序定義一個main()。所以,我假設你要做的是在兩個程序之間共享一個頭文件。在這種情況下,該行添加到b.cpp定義key並重新編譯:

uint32_t key; 

這是不使用頭文件的正常方式。相反,您可以編寫函數以key作爲參數。這樣做會造成一個全局變量,這個變量通常是不被接受的。

extern幾乎總是用於設置一個全局變量(關閉我的頭頂,我想不出任何其他原因使用extern)。但是,如果你想使用extern它通常使用的方式 - 沒有進入它是否應該在所有使用 - 你會做以下幾點:

  • 從兩個文件中的一個取出main()功能,這個答案的目的,我們將從b.cpp中刪除它。
  • 使用以下兩行來編譯和鏈接程序(假設GCC):

    gcc -c -o b.o b.cpp

    gcc a.cpp b.o

-c選項gcc(第一行)表示,「compile only, do not link。 「這是鏈接步驟,用於確定是否定義了所有變量,並且在編譯b.cpp時未定義它們,但是在編譯a.cpp(第二行)時定義了它們。