編譯單位和連結
在 C++ 程式中, 符號 ,例如變數或函式名稱,可以在其範圍內宣告任何次數。 不過,它只能定義一次。 此規則是「一個定義規則」(ODR)。 宣告 會將名稱引入程式,以及足夠的資訊,以便稍後將名稱與定義產生關聯。 定義 引進名稱,並提供建立它所需的所有資訊。 如果名稱代表變數,定義會明確建立儲存體並初始化它。 函 式定義 是由簽章加上函式主體所組成。 類別定義是由類別名稱所組成,後面接著列出所有類別成員的區塊。 (成員函式的主體可選擇性地在另一個檔案中個別定義。
下列範例顯示一些宣告:
int i;
int f(int x);
class C;
下列範例顯示一些定義:
int i{42};
int f(int x){ return x * i; }
class C {
public:
void DoSomething();
};
程式是由一或多個 翻譯單位 所組成。 翻譯單元包含實作檔案及其直接或間接包含的所有標頭。 實作檔案通常副檔名為 .cpp
或 .cxx
。 標頭檔通常具有 或 .hpp
的 .h
副檔名。 編譯器會獨立編譯每個轉譯單位。 編譯完成之後,連結器會將編譯的翻譯單位合併成單 一程式 。 ODR 規則的違規通常會顯示為連結器錯誤。 在多個翻譯單位中定義相同名稱時,就會發生連結器錯誤。
一般而言,讓多個檔案可見變數的最佳方式是在標頭檔中宣告變數。 然後在每個 .cpp
需要宣告的檔案中新增 #include
指示詞。 藉由在標頭內容周圍新增 include guard ,您可確保標頭宣告的名稱只會針對每個轉譯單位宣告一次。 在一個實作檔案中定義名稱。
在 C++20 中, 模組 會引進為標頭檔改善的替代方案。
在某些情況下,您可能需要在檔案中 .cpp
宣告全域變數或類別。 在這些情況下,您需要一種方式來告訴編譯器和連結器名稱具有何種 連結 。 連結的類型會指定物件的名稱只顯示在一個檔案中或所有檔案中。 連結的概念僅適用于全域名稱。 連結的概念不適用於範圍內宣告的名稱。 範圍是由一組括住大括弧所指定,例如在函式或類別定義中。
外部與內部連結
免費函式 是定義于全域或命名空間範圍的函式。 根據預設,非常數全域變數和免費函式具有 外部連結 ;它們可從程式中的任何轉譯單位看到。 沒有其他全域物件可以有該名稱。 具有 內部連結或 沒有連結 的符號只能在宣告它的轉譯單位內顯示。 當名稱具有內部連結時,同名可能會存在於另一個轉譯單位中。 類別定義或函式主體內宣告的變數沒有連結。
您可以藉由明確將全域名稱宣告為 static
,強制具有內部連結。 此關鍵字會將其可見度限制為宣告所在的相同翻譯單位。 在此內容中, static
表示與套用至區域變數時不同的專案。
根據預設,下列物件具有內部連結:
const
物件constexpr
物件typedef
物件static
命名空間範圍中的物件
若要提供 const
物件外部連結,請將它宣告為 extern
,並為其指派值:
extern const int value = 42;
如需詳細資訊,請參閱extern
。
另請參閱
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應