在閱讀一個較大的解決方案中,對于其他文件夾下的.h和.cpp文件,有時候#include“XXX.h”文件,有時候是#include“XXX.cpp”文件,而且二者還不能更換。下面就好好分析一下他們二者的區(qū)別。
?
測試
測試:XXX.h和XXX.cpp有沒有在解決方案里的差別
???????如果 .h 文件和 .cpp 文件都已經(jīng)添加在解決方案里,只要在 main 的頭文件中 include 對應(yīng)的 .h 文件即可。
??如果 .h 文件和 .cpp 文件不在解決方案里,可能在其他文件夾里,單獨(dú) include.h 文件就會報錯“error LNK2019: 無法解析的外部符號”。
????????但是單獨(dú) include.cpp 就能運(yùn)行了,而此時當(dāng)前 main.cpp 里面有沒有對應(yīng)的 .h 頭文件都可以正確運(yùn)行(因?yàn)?.h 文件里有 #pragma once 防止多次定義),
????????這個很好解釋,include 就是把對應(yīng)的代碼拷貝一份進(jìn)去,拷貝之后,自定義函數(shù)的定義本來就在使用前,有沒有頭文件的聲明都可以。為了驗(yàn)證 include 是不是就是將程序拷貝,做了實(shí)驗(yàn)驗(yàn)證。
????????在自定義函數(shù)使用前 #include“XXX.h” 用于函數(shù)的聲明(意思是在 main.cpp 最前面 #include“XXX.h),在 main 函數(shù)結(jié)束之后#include“XXX.cpp”,運(yùn)行果然正確。
??初步結(jié)論:說明當(dāng).h文件和.cpp文件不在解決方案里的時候,#include就是純粹的拷貝復(fù)制工作。但是當(dāng) .h 和 .cpp 文件在解決方案的情況需要進(jìn)一步驗(yàn)證。
????????同時也說明,.cpp 文件有沒有包含進(jìn)工程文件的情況是不同的。
探究
按照所有查到的信息都說明一點(diǎn)內(nèi)容:凡是#include的頭文件,都是把對應(yīng)的文件信息拷貝復(fù)制一份進(jìn)來。顯然這個籠統(tǒng)的概念是不對的。
??源程序->預(yù)處理->編譯和優(yōu)化->生成目標(biāo)文件->鏈接->可執(zhí)行文件
??參考之前我轉(zhuǎn)載的3篇博文C++編譯與鏈接的三部曲(強(qiáng)烈推薦看一看)。大致總結(jié)如下:
?
預(yù)處理(簡單替換)
??預(yù)處理做如下工作:
預(yù)處理器主要負(fù)責(zé)以下的幾處:
1.宏的替換
2.刪除注釋
3.處理預(yù)處理指令,如#include,#ifdef
編譯和優(yōu)化(高級語言->匯編語言)
詞法分析 – 識別單詞,確認(rèn)詞類;比如int i;知道int是一個類型,是一個關(guān)鍵字以及判斷i的名字是否合法。
語法分析 – 識別短語和句型的語法屬性;
語義分析 – 確認(rèn)單詞、短語和句型的語義特征;
代碼優(yōu)化 – 修辭、文本編輯;
代碼生成 – 生成譯文。
內(nèi)聯(lián)函數(shù)的替換就發(fā)生在這一階段。
編譯的另一個重要方面就是編譯單元
??什么是編譯單元呢?簡單來說一個cpp文件就是一個編譯單元。
??在集成式的IDE中,我們往往點(diǎn)擊一下運(yùn)行便可以了,編譯的所有工作都交給了IDE去處理,往往忽略了其中的內(nèi)部流程。
??事實(shí)上編譯每個編譯單元(.cpp)時是相互獨(dú)立的,即每個cpp文件之間是不知道對方的存在的(不考慮#include “xxx.cpp" 這種奇葩的寫法)。
??編譯器會分別將每個編譯單元(.cpp)進(jìn)行編譯,生成相應(yīng)的obj文件,然后鏈接器會將所有的obj文件進(jìn)行鏈接,生成最終可執(zhí)行文件內(nèi)部鏈接與外部鏈接。
??這里能作為單獨(dú)編譯單元的是添加進(jìn)工程的cpp文件,外部文件夾的cpp文件并不單獨(dú)成為編譯單元。
?
生成目標(biāo)文件(匯編語言->二進(jìn)制機(jī)器語言)
??匯編過程實(shí)際上指把匯編語言代碼翻譯成目標(biāo)機(jī)器指令的過程。
??在最終的目標(biāo)文件中,編譯器把一個cpp編譯為目標(biāo)文件的時候,除了要在目標(biāo)文件里寫入cpp里包含的數(shù)據(jù)和代碼,還要至少提供3個表:
未解決符號表;
導(dǎo)出符號表;
地址重定向表
未解決符號表提供了所有在該編譯單元里引用但是定義并不在本編譯單元里的符號及其出現(xiàn)的地址;
??導(dǎo)出符號表提供了本編譯單元具有定義,并且愿意提供給其他編譯單元使用的符號及其地址。
??地址重定向表提供了本編譯單元所有對自身地址的引用的記錄。
??這就是不同cpp之間的通訊方式。
從這個定義方式上看,主cpp文件和其他所有cpp文件都是平等的關(guān)系,只不過主cpp里面包含了main函數(shù)而已,而main函數(shù)和其他所有函數(shù)也是平等的,只不過只有main函數(shù)可以作為工程的入口函數(shù)而已。
鏈接(匯總成一個目標(biāo)文件)
由匯編程序生成的目標(biāo)文件并不能立即就被執(zhí)行,其中可能還有許多沒有解決的問題。例如,某個源文件中的函數(shù)可能引用了另一個源文件中定義的某個符號(如變量或者函數(shù)調(diào)用等);在程序中可能調(diào)用了某個庫文件中的函數(shù),等等。所有的這些問題,都需要經(jīng)鏈接程序的處理方能得以解決。
??由此,我們可以理解了經(jīng)常報錯的一些情況,就是未解決符號表和導(dǎo)出符號表之間沒有定義或者重復(fù)定義的情況的。
?文章來源:http://www.zghlxwxcb.cn/news/detail-447227.html
外部文件夾的h和cpp文件
外部文件夾的cpp文件并不能生成單獨(dú)的編譯文件,所以,不參與未解決符號表和導(dǎo)出符號表的生成,而#include外部的h頭文件也只是復(fù)制進(jìn)來頭文件中的函數(shù)聲明而已,沒有定義。所以當(dāng)需要使用外部文件夾的cpp文件的時候,直接在頭部加上#include cpp文件,或者在頭部#include h文件,尾部#include cpp文件,就相當(dāng)于我們平時寫的自定義函數(shù)一樣。
?文章來源地址http://www.zghlxwxcb.cn/news/detail-447227.html
到了這里,關(guān)于C++ 中到底是應(yīng)該include .h文件還是應(yīng)該include .cpp文件的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!