您好,歡迎訪問(wèn)seo優(yōu)化易企優(yōu)搜索引擎優(yōu)化系統(tǒng)!
咨詢熱線:400-844-5354
 
微信二維碼
咨詢熱線:400-844-5354

編譯器需要C文件與頭文件(即.h)

簡(jiǎn)單來(lái)說(shuō),要了解C文件和頭文件(即.h)的區(qū)別,首先需要了解編譯器的工作過(guò)程。 一般來(lái)說(shuō),編譯器會(huì)做以下幾個(gè)過(guò)程:

1.預(yù)處理階段

2. 詞法分析階段

3、編譯階段,先編譯成純匯編語(yǔ)句,再編譯成與CPU相關(guān)的二進(jìn)制代碼,生成各個(gè)目標(biāo)文件(.obj文件)

4、在連接階段,對(duì)每個(gè)目標(biāo)文件中的每段代碼進(jìn)行絕對(duì)地址定位,生成特定平臺(tái)相關(guān)的可執(zhí)行文件。 當(dāng)然也可以用于最后生成純二進(jìn)制代碼,即去掉文件格式信息。 (生成.exe文件)

編譯器在編譯的時(shí)候是以C文件為單位的,也就是說(shuō),如果你的工程中沒(méi)有C文件,那么你的工程是不會(huì)被編譯的,而鏈接器是以目標(biāo)文件為單位的,它會(huì)每個(gè)目標(biāo)文件重新定位函數(shù)和變量以生成最終的可執(zhí)行文件。 PC端的程序開(kāi)發(fā)一般都有一個(gè)main函數(shù)。 這是每個(gè)編譯器的約定。 當(dāng)然,如果你自己寫鏈接描述文件,你可以使用main函數(shù)作為程序入口! ! ! !

(main.c文件目標(biāo)文件可執(zhí)行)

有了這些基礎(chǔ)知識(shí),我們言歸正傳,為了生成最終的可執(zhí)行文件,我們需要一些目標(biāo)文件,也就是C文件,而這些C文件需要一個(gè)main函數(shù)作為可執(zhí)行程序的入口,那么我們將從一個(gè)C文件開(kāi)始,假設(shè)這個(gè)C文件的內(nèi)容如下:

#

# “。H”

int main(int argc, char **argv)

{

測(cè)試 = 25;

("測(cè)試............%d\n",測(cè)試);

}

.h頭文件內(nèi)容如下:

內(nèi)部測(cè)試;

現(xiàn)在以這個(gè)例子來(lái)說(shuō)明編譯器的工作:

1.在預(yù)處理階段,編譯器以C文件為單位,首先讀取C文件,發(fā)現(xiàn)第一句和第二句包含頭文件,就會(huì)在所有搜索路徑中搜索這兩個(gè)文件,并找到它們,它會(huì)處理對(duì)應(yīng)頭文件中的宏、變量、函數(shù)聲明、嵌套頭文件包含等,檢測(cè)依賴關(guān)系,進(jìn)行宏替換,看是否有重復(fù)的定義和聲明,最后將那些文件放入All這些東西被掃描到當(dāng)前的 C 文件中,形成一個(gè)中間“C 文件”

2.在編譯階段,在上一步中,相當(dāng)于把頭文件中的test變量掃描到一個(gè)中間C文件中,那么test變量就變成了這個(gè)文件中的全局變量,此時(shí)所有的中間C文件的所有變量和函數(shù)分配空間,將每個(gè)函數(shù)編譯成二進(jìn)制代碼,并根據(jù)特定的目標(biāo)文件格式生成目標(biāo)文件。 在這種格式的目標(biāo)文件中,對(duì)各個(gè)全局變量和函數(shù)進(jìn)行符號(hào)描述,并將這些二進(jìn)制代碼按照一定的編譯標(biāo)準(zhǔn)組織成一個(gè)目標(biāo)文件

3. 在連接階段,根據(jù)一些參數(shù)將上一步生成的目標(biāo)文件連接起來(lái),生成最終的可執(zhí)行文件。 主要任務(wù)是將各個(gè)目標(biāo)文件的函數(shù)、變量等重新定位,相當(dāng)于將二進(jìn)制代碼按照一定的規(guī)范組合成一個(gè)文件,再回到C文件寫什么的話題頭文件:理論上來(lái)說(shuō),只要C文件和頭文件里的內(nèi)容是C語(yǔ)言支持的,不管寫什么都可以,比如你把函數(shù)體寫在頭文件里,只要這個(gè)頭文件包含在任何C文件中,函數(shù)就可以編譯成目標(biāo)文件的一部分(編譯是基于C文件的,如果不在任何C文件中如果這個(gè)頭文件包含在,這段代碼沒(méi)用),你可以在C文件中進(jìn)行函數(shù)聲明、變量聲明和結(jié)構(gòu)聲明,這不是問(wèn)題! ! !

那為什么一定要分頭文件和C文件呢? 為什么函數(shù)、變量聲明、宏聲明和結(jié)構(gòu)聲明一般都在頭文件中進(jìn)行? 而在C文件中定義變量,函數(shù)實(shí)現(xiàn)呢? ? 原因如下:

1.如果一個(gè)函數(shù)體是在頭文件中實(shí)現(xiàn)的,如果在多個(gè)C文件中被引用,同時(shí)編譯多個(gè)C文件,生成的目標(biāo)文件會(huì)鏈接成一個(gè)可執(zhí)行文件,每次引用this在頭文件的C文件生成的目標(biāo)文件中,有一段這個(gè)函數(shù)的代碼。 如果這個(gè)函數(shù)沒(méi)有定義為局部函數(shù),那么在鏈接的時(shí)候,會(huì)發(fā)現(xiàn)多個(gè)相同的函數(shù),就會(huì)報(bào)錯(cuò)。

2、如果在頭文件中定義了一個(gè)全局變量,并為該全局變量賦了初值,那么在引用這個(gè)頭文件的多個(gè)C文件中,存在同名變量名的副本。 關(guān)鍵是給變量賦初值。 因此,編譯器會(huì)將這個(gè)變量放入DATA段。 最后,在連接階段,DATA段中會(huì)出現(xiàn)多個(gè)相同的變量。 它不能將這些變量統(tǒng)一為一個(gè)變量,即只為這個(gè)變量分配一個(gè)空間。 而不是多個(gè)空格,如果這個(gè)變量在頭文件中沒(méi)有賦初值,編譯器會(huì)把它放在

編譯器需要C文件與頭文件(即.h)

在BSS段中,鏈接器只會(huì)為BSS段中的多個(gè)同名變量分配一個(gè)存儲(chǔ)空間。

3、如果在一個(gè)C文件中聲明了宏、結(jié)構(gòu)體、函數(shù)等,那么如果我要在另一個(gè)C文件中引用相應(yīng)的宏和結(jié)構(gòu)體,就必須再做一次重復(fù)的工作。 如果我改了一個(gè)C文件而忘記改其他C文件中的語(yǔ)句,那問(wèn)題就大了,程序的邏輯會(huì)變得你無(wú)法想象。 如果你把這些的東西放在一個(gè)頭文件里,你要用它的C文件,只需要引用一個(gè)就OK了! ! !這不是很方便嗎? 當(dāng)你想改變一個(gè)語(yǔ)句時(shí),你只需要移動(dòng)頭文件。

4.在頭文件中聲明結(jié)構(gòu)、函數(shù)等。 當(dāng)你需要把你的代碼打包成一個(gè)庫(kù)讓別人使用你的代碼,而你又不想把源碼公布出來(lái),別人怎么用你的庫(kù)呢? 也就是如何使用你庫(kù)中的每一個(gè)函數(shù)? ? 一種方法是將源代碼公開(kāi),其他人可以隨意使用。 另一種是提供頭文件,別人可以從頭文件中讀到你的函數(shù)原型,從而知道如何調(diào)用你寫的函數(shù),就像你調(diào)用函數(shù)一樣。 ,里面的參數(shù)是什么? ? 你怎么知道? ? 不是看別人頭文件中的相關(guān)語(yǔ)句! ! ! 當(dāng)然,這些東西都成了C標(biāo)準(zhǔn),即使不看別人的頭文件,也能知道怎么用。

C語(yǔ)言中.c和.h文件的混淆

本質(zhì)上沒(méi)有什么區(qū)別。只是籠統(tǒng)地說(shuō):.h文件是一個(gè)頭文件,里面包含了函數(shù)聲明、宏定義、結(jié)構(gòu)體定義等。

.c文件是程序文件,包含函數(shù)實(shí)現(xiàn)、變量定義等內(nèi)容。 并且后綴是什么并不重要,但是編譯器會(huì)默認(rèn)對(duì)具有某些后綴的文件采取某些操作。 您可以強(qiáng)制編譯器將任何后綴的文件編譯為c文件。

將這兩個(gè)文件分開(kāi)編寫是一種很好的編程風(fēng)格。

而且,比如我在aaa.h中定義了一個(gè)函數(shù)聲明,然后我在aaa.h的同級(jí)目錄下創(chuàng)建了aaa.c。 這個(gè)函數(shù)的實(shí)現(xiàn)定義在aaa.c中,然后main函數(shù)位于.c文件中的#this aaa.h,然后我就可以使用這個(gè)函數(shù)了。 Main 會(huì)在運(yùn)行時(shí)找到這個(gè)定義這個(gè)函數(shù)的 aaa.c 文件。

這是因?yàn)椋?/p>

main函數(shù)是標(biāo)準(zhǔn)C/C++程序的入口,編譯器會(huì)先找到該函數(shù)所在的文件。

假設(shè)編譯器在編譯.c(包括main())時(shí),找到mylib.h(里面聲明了函數(shù)void test()),那么編譯器就會(huì)按照預(yù)設(shè)的路徑(路徑列表和代碼文件所在的路徑) )尋找同名的實(shí)現(xiàn)文件(擴(kuò)展名.cpp或.c,本例為mylib.c),如果找到,找到其中的函數(shù)(本例為void test()),然后繼續(xù)編譯; 如果在指定目錄下找不到實(shí)現(xiàn)文件,或者在本文件及后續(xù)文件中找不到實(shí)現(xiàn)代碼,則返回編譯錯(cuò)誤。 其實(shí)這個(gè)過(guò)程可以“看”成一個(gè)文件拼接過(guò)程,聲明和實(shí)現(xiàn)分別寫在頭文件和C文件中,或者兩者同時(shí)寫在頭文件中,理論上是沒(méi)有的本質(zhì)區(qū)別。

以上就是所謂的動(dòng)態(tài)方法。

對(duì)于靜態(tài)方法,基本上所有的C/C++編譯器都支持一種叫做Link的鏈接方法,也就是所謂的靜態(tài)鏈接。

這樣,我們所要做的就是編寫包含函數(shù)、類等聲明的頭文件(ah、bh、...)及其對(duì)應(yīng)的實(shí)現(xiàn)文件(a.cpp、b.cpp、...)。 .), 編譯器會(huì)把它編譯成靜態(tài)庫(kù)文件(a.lib,b.lib,...)。 在后續(xù)的代碼復(fù)用過(guò)程中,我們只需要提供相應(yīng)的頭文件(.h)和相應(yīng)的庫(kù)文件(.lib),就可以使用過(guò)去的代碼了。

與動(dòng)態(tài)方法相比,靜態(tài)方法的優(yōu)勢(shì)在于實(shí)現(xiàn)代碼的隱蔽性,即C++所提倡的“接口對(duì)外,實(shí)現(xiàn)代碼不可見(jiàn)”。 有利于庫(kù)文件的轉(zhuǎn)發(fā)。

許多人會(huì)反對(duì)說(shuō)難題中最難的部分是基本概念,但事實(shí)確實(shí)如此。 高中學(xué)物理的時(shí)候,老師講的是概念,概念要搞清楚,難的就變簡(jiǎn)單了。 如果你能分析清楚一個(gè)物理問(wèn)題有幾個(gè)物理過(guò)程,每個(gè)過(guò)程都遵守那個(gè)物理定律(比如動(dòng)量守恒、牛二定律、能量守恒定律),那么很容易把這個(gè)過(guò)程的方程按照定律 ,N個(gè)過(guò)程一定是N個(gè)N元方程,問(wèn)題就很容易解決了。 就算是高中物理競(jìng)賽題,最難的也無(wú)非是:

(一)混淆概念,導(dǎo)致無(wú)法分析幾個(gè)物理過(guò)程,或者某個(gè)物理過(guò)程所遵循的物理規(guī)律;

(2) 有高階方程,方程即使列出也解不出來(lái)。 后者已經(jīng)屬于數(shù)學(xué)的范疇,所以最難的是要把握清楚的概念;

編程也是如此。 概念清楚的話,基本沒(méi)有問(wèn)題(數(shù)學(xué)上會(huì)比較難,比如算法的選擇,時(shí)間空間和效率的權(quán)衡,穩(wěn)定性和資源的平衡)。 然而,要掌握一個(gè)清晰的概念卻不是那么容易。 看看下面的例子,看看你是否有一個(gè)清晰透徹的理解。

//啊無(wú)效 foo(); //ac # "ah" //我的問(wèn)題出來(lái)了:這句話到底有沒(méi)有必要?

無(wú)效的 foo()

{ ; } //main.c # "ah" int main(int argc, char *argv[]) {foo(); 0; }

對(duì)于上面的代碼,請(qǐng)回答三個(gè)問(wèn)題:

. (1)ac中#“啊”這句是多余的嗎?

(2)為什么在xx.c中經(jīng)??吹綄?duì)應(yīng)的xx.h?

編譯器需要C文件與頭文件(即.h)

(3)如果不是用ac寫的,編譯器會(huì)自動(dòng)把.h文件的內(nèi)容綁定到同名的.c文件中嗎? (慣于)

(以上3個(gè)問(wèn)題請(qǐng)仔細(xì)思考10分鐘,不要急著看下面的解釋。:) 想的越多理解的越深。 )

好了,是時(shí)候了! 請(qǐng)忘掉以上3個(gè)問(wèn)題以及你對(duì)這三個(gè)問(wèn)題的想法,然后慢慢聽(tīng)我說(shuō)。 正確的觀念是:在C編譯器看來(lái),.h和.c都是浮云,改名為.txt或.doc也沒(méi)有太大區(qū)別。 換句話說(shuō),.h和.c之間沒(méi)有必然聯(lián)系。 一般.h包含定義在同名.c文件中的變量、數(shù)組、函數(shù)的聲明,以及需要在.c之外使用的聲明。 這個(gè)語(yǔ)句有什么用? 只是為了便于參考需要這些聲明的地方。 因?yàn)楹?“xx.h”的實(shí)際意思是刪除當(dāng)前行,在當(dāng)前行位置原封不動(dòng)的插入xx.h中的內(nèi)容。 由于我要寫這些函數(shù)聲明的地方很多(xx.c中每一個(gè)調(diào)用函數(shù)的地方都必須在使用前聲明),所以使用#"xx.h"宏可以簡(jiǎn)化很多行代碼——讓預(yù)處理器替換自身。 也就是說(shuō),xx.h其實(shí)只是調(diào)用了xx.c中需要寫函數(shù)聲明的地方(可以少寫幾行)。 至于這個(gè).h文件是誰(shuí)的,是.h還是.c,或者跟這個(gè).h有關(guān)系嗎?同名的.c沒(méi)有必然關(guān)系。

所以你可能會(huì)說(shuō):嗯? 然后我平時(shí)就是想調(diào)用xx.c中的某個(gè)函數(shù),但是把xx.h文件刪掉了。 宏替換后不是有很多無(wú)用的語(yǔ)句嗎? 是的,確實(shí)引入了很多垃圾,但是卻省了很多筆墨,整個(gè)布局看起來(lái)也干凈多了。 這就是魚和熊掌不可兼得的原因。 反正多聲明(.h一般只用來(lái)放聲明,不放定義,看我的書《過(guò)馬路,左看右看》)無(wú)傷大雅,不會(huì)影響編譯,何樂(lè)而不為呢?

回過(guò)頭來(lái)看以上三個(gè)問(wèn)題,是不是很容易回答呢? 答:不一定。 這個(gè)例子顯然是多余的。 但是如果.c中的函數(shù)還需要調(diào)用同一個(gè).c中的其他函數(shù),那么這個(gè).c往往會(huì)和.h同名,所以不用擔(dān)心聲明和調(diào)用的順序(C 要求在使用前必須聲明,同名的.h一般會(huì)放在.c)的開(kāi)頭。 許多項(xiàng)目甚至同意將這種寫法作為代碼規(guī)范來(lái)規(guī)范清晰的代碼。

答:1已經(jīng)回答了。

答:沒(méi)有。問(wèn)這個(gè)問(wèn)題的人肯定是不清楚,或者就是想渾水摸魚。 很煩人的是中國(guó)很多考試都有這樣的爛題。 生怕別人概念清楚,肯定會(huì)把考生搞糊涂。

搞清楚語(yǔ)法和概念說(shuō)起來(lái)容易做起來(lái)難。 有三招:工作不要發(fā)呆,抽空多思考,多看書;

讀書要讀好書,問(wèn)人要問(wèn)強(qiáng)人。 壞書壞人會(huì)給你錯(cuò)誤的觀念,誤導(dǎo)你;

勤能補(bǔ)拙是一種很好的修養(yǎng),一分耕耘一分收獲;

(1) 通過(guò)頭文件調(diào)用庫(kù)函數(shù)。 在很多場(chǎng)合,源代碼是不方便(或不允許)發(fā)布給用戶的,只要提供頭文件和二進(jìn)制庫(kù)給用戶即可。 用戶只需要根據(jù)頭文件中的接口聲明調(diào)用庫(kù)函數(shù)即可,無(wú)需關(guān)心接口是如何實(shí)現(xiàn)的。 編譯器從庫(kù)中提取相應(yīng)的代碼。

(2) 頭文件可以加強(qiáng)類型安全檢查。 如果接口的實(shí)現(xiàn)或使用方式與頭文件中的聲明不一致,編譯器會(huì)指出錯(cuò)誤。 這個(gè)簡(jiǎn)單的規(guī)則可以大大減輕程序員調(diào)試和改錯(cuò)的負(fù)擔(dān)。

頭文件用于存儲(chǔ)函數(shù)原型。

頭文件與源文件有什么關(guān)系?

這道題其實(shí)是說(shuō)已知的頭文件“啊”聲明了一系列函數(shù)(只有函數(shù)原型,沒(méi)有函數(shù)實(shí)現(xiàn)),而這些函數(shù)是在“b.cpp”中實(shí)現(xiàn)的,那么如果我要在“c.cpp”中在"ah"中聲明的"b.cpp"中實(shí)現(xiàn)的函數(shù)通常在"c.cpp"#"ah"中使用,那么c.cpp如何找到b.cpp中的實(shí)現(xiàn)呢?

事實(shí)上,.cpp 和.h 文件名沒(méi)有任何直接關(guān)系,許多編譯器可以接受其他擴(kuò)展名。

譚浩強(qiáng)先生在《C程序設(shè)計(jì)》一書中提到,編譯器在進(jìn)行預(yù)處理時(shí),需要對(duì)#命令進(jìn)行“文件包含處理”:將.h的全部?jī)?nèi)容復(fù)制到#

“。H”。 這也解釋了為什么很多編譯器不關(guān)心這個(gè)文件的后綴是什么——因?yàn)?是為了完成一個(gè)“復(fù)制和插入代碼”的工作。

程序編譯時(shí)不會(huì)在b.cpp文件中尋找函數(shù)實(shí)現(xiàn),只有在鏈接時(shí)才做這個(gè)工作。 我們?cè)赽.cpp或c.cpp中使用#"ah"來(lái)實(shí)際引入相關(guān)聲明,這樣編譯就可以通過(guò),程序不關(guān)心它是在哪里實(shí)現(xiàn)的,是如何實(shí)現(xiàn)的。 源文件編譯后,生成目標(biāo)文件(.o 或.obj 文件)。 在目標(biāo)文件中,這些函數(shù)和變量被視為符號(hào)。 鏈接的時(shí)候需要指定需要連接哪個(gè).o或者.obj文件(這里是b.cpp生成的.o或者.obj文件),這時(shí)候鏈接器會(huì)去這個(gè).o或者.obj file 查找b.cpp中實(shí)現(xiàn)的函數(shù),并構(gòu)建到.cpp中指定的可執(zhí)行文件中。 (很重要)

在VC中,一堆情況不需要你自己寫,你只需要包含所有需要的文件,VC會(huì)自動(dòng)幫你寫。

通常,編譯器會(huì)在每個(gè) .o 或 .obj 文件中查找所需的符號(hào),而不是只查找某個(gè)文件或找到一個(gè)文件就不找。 因此,如果在幾個(gè)不同的文件中實(shí)現(xiàn)了同一個(gè)功能,或者定義了同一個(gè)全局變量,鏈接時(shí)會(huì)提示“”。

最后,無(wú)論你是在職場(chǎng)成長(zhǎng)還是在大學(xué)的入門階段,C/C++都是一門編程語(yǔ)言,不僅可以增強(qiáng)你的思維能力,還可以為編程打下堅(jiān)實(shí)的基礎(chǔ)。 如果你想做軟件開(kāi)發(fā),成為核心程序員, C/C++是更好的選擇。 作者有一個(gè)千人C/C++程序員的Q群(Q船有線:C語(yǔ)言編程學(xué)習(xí)聚集地(默默建立))如果覺(jué)得自學(xué)C/C++語(yǔ)言有難度,有興趣的小伙伴學(xué)習(xí)或者學(xué)習(xí)C/C++編程的可以進(jìn)來(lái)交流。 下面給大家分享一下C/C++的學(xué)習(xí)路線圖:

TAG標(biāo)簽:源代碼是什么意思 
聲明:本文"編譯器需要C文件與頭文件(即.h)":http://dhooder.com/html/show850.html內(nèi)容和圖片部分來(lái)自互聯(lián)網(wǎng),若本站收錄的信息無(wú)意侵犯了貴司版權(quán),請(qǐng)給我們來(lái)信,我們會(huì)及時(shí)處理和回復(fù)。

上一頁(yè):SEO優(yōu)化技巧:關(guān)鍵詞方面詳解!

下一頁(yè):站外優(yōu)化攻略:關(guān)鍵詞、外鏈、社交媒體

Top