簡體   English   中英

C++ 包含文件

[英]C++ Include files

我知道在頭文件中提供定義允許其他文件引用它們,然后鏈接器將所有目標文件添加在一起並稍后提供定義。

這只是為了我們可以在其他庫中的其他地方重用實現嗎?

如果我們不使用頭文件或濫用它們並將所有代碼都放在其中,即完整的實現會發生什么? 編譯每個文件時是否需要更長的時間,因為需要在對等文件的基礎上編譯完整定義? 它會導致鏈接器出現問題,因為它是同一實現的多個編譯版本嗎?

這如何與模板一起使用?

布萊爾

每次新的編譯目標包含該頭文件時,頭文件中的任何代碼都會被編譯,因此至少是的,您將花費更長的時間來編譯。 不過,這通常不是重要的問題。

假設你有這個標題:

int f_header() {
    return 0;
}

以及這些源文件:

/* a.cpp */
#include "myheader.h"
int f_a() {
    return f_header();
}


/* b.cpp */
#include "myheader.h"
int f_b() {
    return f_header();
}

現在,當您編譯這些源代碼中的每一個時,編譯都會成功。 但是,當您鏈接程序時,鏈接器將失敗,因為您將提供函數f_header()兩次。

模板是一種特殊情況,因為它們實際上並不是代碼,而是為基於不同類型生成的代碼提供了模板。 盡管當多個源文件使用相同類型的源文件時會出現重復,但編譯器能夠為您處理這種特殊情況。

拆分源文件和頭文件中的代碼是(是?)歷史上或多或少需要的。 它允許編譯器單獨編譯大項目的代碼單元,整個項目太大而無法一次編譯。

它允許緩存沒有改變的編譯單元,這進一步縮短了編譯時間。

所以從技術上講,編譯器會看到一整套不同的編譯單元。 如果您提供相同定義的多個實現,則編譯器不會告訴您什么。 但是一旦鏈接器將編譯單元包裝成單個可執行文件,它就會絆倒它。

今天,像 C# 或 Java 這樣的“現代”語言擺脫了這種歷史限制。 但是 C++ 是一種復雜的語言,即使對於編譯器也是如此,所以這些優勢在某種程度上仍然是相關的。

編譯器一次編譯一個文件。 編譯器正在解析的源文件可能包含其他文件,但所有這些包含的文件在預編譯階段都被“扁平化”為單個源,並且編譯器“看到”一個單一的代碼實體。

由於上述原因,代碼是在 .cpp 還是在 .h 文件中對編譯器來說無關緊要,因為編譯器不會進行區分。 但是如果一些函數定義或一些變量定義在 .h 文件中,問題就會出現在鏈接階段。

鏈接器看不到源文件,但可以看到目標文件 (.obj),這是編譯器生成的結果。 鏈接器知道每個目標文件中的每個函數和每個變量,而鏈接器的工作是將它們全部綁定(或鏈接)在一個可執行文件中。 如果在不同的目標文件中有多個同名的變量或函數,鏈接器將無所適從,並且會聲明錯誤。 可以通過一個選項強制鏈接器忽略所有額外的變量和函數,但不要輕易使用該選項。 兩個同名的函數實際上可能完全不同,忽略其中一個會導致各種錯誤。

另一方面,模板根本不是函數。 它們是實際功能的藍圖。 當編譯器遇到模板時,不會發生任何實質性的事情。 只有當模板實例化為實際函數時,編譯器才會生成這樣的函數。 因為這個模板可以駐留在頭文件中就好了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM