日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

c 包含其他文件_C/C++编程笔记:C/C++的编译和链接,计算机专业大学生必备知识...

發(fā)布時(shí)間:2024/7/23 c/c++ 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c 包含其他文件_C/C++编程笔记:C/C++的编译和链接,计算机专业大学生必备知识... 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

C/C++文件

C/C++程序文件包括 .h .c .hpp .cpp,其中源文件(.c .cpp)是基本的編譯單元,頭文件(.h .hpp)不會(huì)被編譯器編譯。

C/C++項(xiàng)目構(gòu)建(build)過(guò)程,分為以下幾個(gè)步驟 預(yù)處理 → 編譯 → 鏈接。

預(yù)編譯

預(yù)編譯的過(guò)程可以理解為編譯器(實(shí)際上是預(yù)處理器,這里統(tǒng)稱(chēng)為編譯器就可以了)在正式編譯之前處理C/C++文件中的預(yù)處理命令,即#開(kāi)頭的代碼。

常用的幾個(gè)預(yù)處理命令如下:

#include ......

#ifdef ...... #else......#endif

#define ......

#pragma ......

舉個(gè)例子,下面是個(gè)很簡(jiǎn)單的類(lèi)定義:

MyClass.h

MyClass.cpp

預(yù)編譯完成后的樣子:

可以看到編譯器把.h文件替換到了.cpp文件中的#include 位置上,把DEFAULT_VALUE定義的值也替換到了相應(yīng)的位置。

編譯

預(yù)編譯之后,編譯器會(huì)編譯每個(gè)源文件(.c .cpp),如果編譯成功,會(huì)生成對(duì)應(yīng)的目標(biāo)文件,Linux為.o文件,Windows平臺(tái)下為.obj文件。

以Linux平臺(tái)為例,上面的MyClass.cpp編譯完成后會(huì)生成MyClass.o文件

使用objdump可以看到目標(biāo)文件MyClass.o的內(nèi)容

編譯器會(huì)把MyClass::Fun()的名字改成_ZN7MyClass3FunEv,這個(gè)過(guò)程叫Mangle,由于C++支持重載,覆蓋等特性,所以編譯器必須把函數(shù)用一個(gè)唯一的標(biāo)識(shí)表示。這個(gè)字符串就是編譯器生成的唯一標(biāo)識(shí)。

這里還要單獨(dú)說(shuō)一下頭文件,頭文件的既然不是編譯單元,那么它的作用是什么?

頭文件就是負(fù)責(zé)”聲明“,編譯器在編譯MyClass.cpp的時(shí)候,對(duì)于MyClass這個(gè)類(lèi)以及Fun()這個(gè)成員函數(shù),編譯器必須找到它的聲明,這個(gè)函數(shù)才能被正確編譯。

如果有其他cpp需要使用MyClass這個(gè)類(lèi)的時(shí)候,也需要它的的聲明。例如

main.cpp

加上#include "MyClass.h" 編譯器在編譯main.cpp的時(shí)候才知道怎么編譯MyClass這個(gè)類(lèi)。MyClass.h里聲明是不會(huì)真正被編譯到main.o中,.h文件中的內(nèi)容在目標(biāo)文件中只是以列表的形式存在,這個(gè)表在后面鏈接時(shí)會(huì)用到。

當(dāng)然,頭文件不僅可以用來(lái)聲明,還可以定義(定義全局變量,全局函數(shù)等),在頭文件中的定義要小心,可能會(huì)引起鏈接錯(cuò)誤。

鏈接

鏈接就是將一堆目標(biāo)文件加靜態(tài)庫(kù)文件裝配成可執(zhí)行文件的過(guò)程。(或者是裝配成靜態(tài)/動(dòng)態(tài)庫(kù)的過(guò)程)

上面兩個(gè)cpp分別被編譯成了MyClass.o, 和main.o,我們要生成可執(zhí)行程序的話,就必須經(jīng)過(guò)鏈接的過(guò)程,把兩個(gè)目標(biāo)文件合成一個(gè)可執(zhí)行文件。

main.o中,main函數(shù)會(huì)構(gòu)造MyClass, 并且調(diào)用Fun()函數(shù),那么main就根據(jù)MyClass.h生成的表,找到MyClass.o中的函數(shù),這個(gè)就是鏈接器要做的工作。

常見(jiàn)錯(cuò)誤

構(gòu)建c/c++工程的時(shí)候,最常見(jiàn)的就是兩種錯(cuò)誤:

-- 編譯錯(cuò)誤,在編譯過(guò)程中產(chǎn)生的錯(cuò)誤,通常是語(yǔ)法錯(cuò)誤,沒(méi)有聲明,重復(fù)聲明導(dǎo)致編譯目標(biāo)文件錯(cuò)誤

其中沒(méi)有聲明通常是由于沒(méi)有#include相應(yīng)的頭文件,或者頭文件缺少相應(yīng)的聲明。

而重復(fù)聲明通常是#include了相同的頭文件,比如 B.h 和 C.h 都包含 A.h,然后 main.h 包含了 B.h 和 C.h,這就導(dǎo)致A.h 在main中被包含了兩次。

解決這個(gè)問(wèn)題的方法是可以在所有.h文件的第一行加上

#pragmaonce

或者,使用#ifndef ... #define ... #endif 語(yǔ)句塊

-- 鏈接錯(cuò)誤,常見(jiàn)的錯(cuò)誤也是兩種,沒(méi)有定義和重復(fù)定義,和上面的沒(méi)有聲明,重復(fù)聲明類(lèi)似。(這里定義指的就是函數(shù)實(shí)現(xiàn))

先討論沒(méi)有定義(undefined reference to xxx)

通常是因?yàn)楹瘮?shù)有聲明,而且被使用了,但是沒(méi)有被定義。比如上面MyClass.cpp中,如果Fun()沒(méi)有被實(shí)現(xiàn)的話,MyClass.cpp和main.cpp編譯時(shí)都不會(huì)報(bào)錯(cuò),但是鏈接時(shí)會(huì)報(bào)告找不到Fun()。

當(dāng)然,如果Fun()沒(méi)被main.cpp調(diào)用的話,即使不實(shí)現(xiàn)它,整個(gè)構(gòu)建過(guò)程也不會(huì)出錯(cuò),因?yàn)殒溄悠鞲静粫?huì)去找這個(gè)函數(shù)的定義。

然后是重復(fù)定義(multiple definition)

指的一份相同的定義在兩個(gè)目標(biāo)文件中都存在,鏈接的時(shí)候鏈接器不知道時(shí)用哪個(gè)了。這種問(wèn)題通常由于全局函數(shù),和全局變量定義在了頭文件中。導(dǎo)致多個(gè)目標(biāo)文件包含相同的全局函數(shù)和全局變量的定義。

解決方法就是在頭文件中聲明,定義放到cpp文件中,或者為定義加上const 或 static這樣的修飾符,鏈接時(shí)會(huì)對(duì)這些帶有const和修飾符的變量特殊處理的。

const只適用于定義常量變量,static定義的是靜態(tài)全局變量,只在當(dāng)前cpp有效,所以鏈接它也不會(huì)被別的目標(biāo)文件鏈接,就不會(huì)有重復(fù)定義的問(wèn)題了。

總之在頭文件中定義變量和函數(shù)要特別主意,可能會(huì)導(dǎo)致鏈接錯(cuò)誤。

當(dāng)然也不是所有定義都不能放到頭文件中,比如剛才說(shuō)的const常量,static全局變量就是例外,還有內(nèi)聯(lián)函數(shù),可以定義在.h文件中,因?yàn)閮?nèi)聯(lián)函數(shù)會(huì)被拷貝到每個(gè)目標(biāo)文件中,也不會(huì)參與鏈接的過(guò)程。

還有模板類(lèi)必須放在頭文件中定義,這個(gè)下面會(huì)討論這個(gè)。

關(guān)于模板,靜態(tài)成員變量

模板類(lèi)模板函數(shù)必須聲明和定義在頭文件中,原因是什么,舉個(gè)例子,假設(shè)MyClass是模板類(lèi)

MyClass.h

MyClass.cpp

main.cpp

編譯的時(shí)候沒(méi)有問(wèn)題,但是鏈接時(shí)會(huì)報(bào)錯(cuò),main.cpp找不到MyClass::Fun(),如下圖

MyClass雖然定義了Fun函數(shù),但是MyClass.o中存在MyClass::Fun(),而根據(jù)MyClass.h文件,main.o中需要找到MyClass::Fun()的定義

結(jié)果鏈接器哪都找不到,只好報(bào)錯(cuò)了。(實(shí)際上通過(guò)objdump查看MyClass.o,編譯器都沒(méi)有生成MyClass::Fun(),因?yàn)榫幾g器認(rèn)為這個(gè)函數(shù)沒(méi)人使用,就直接優(yōu)化掉了)

如果非得在cpp中定義模板類(lèi)的成員函數(shù)呢,有一種方法就是要顯示的在cpp文件中聲明,比如

MyClass.cpp

加上下面這行就不會(huì)有問(wèn)題了,但是缺點(diǎn)就是開(kāi)發(fā)MyClass的程序員無(wú)從知道其他類(lèi)是怎么使用這個(gè)模板的,不可能把所有可能的模板參數(shù)全都一一的列在這里。

所以模板類(lèi)的定義還是要寫(xiě)在.h文件中,

那么如果main.cpp使用到了MyClass, 另外一個(gè)cpp也使用到了MyClass,會(huì)不會(huì)產(chǎn)生重復(fù)代碼導(dǎo)致重復(fù)定義呢,不會(huì),編譯器會(huì)處理好模板類(lèi)的。

下面是靜態(tài)成員變量,為什么靜態(tài)成員變量的定義要放在cpp里,(模板類(lèi)的靜態(tài)成員變量除外)

靜態(tài)成員變量和靜態(tài)全局成員變量不同。

靜態(tài)成員變量的作用域可以是整個(gè)工程,而靜態(tài)全局變量的作用域只是當(dāng)前的cpp。所以靜態(tài)成員變量定義在.h中就會(huì)發(fā)生重定義錯(cuò)誤。

想要在程序員生涯內(nèi)有更高的成就的話,C/C++就是一個(gè)既可以強(qiáng)化思維能力,又可以打好編程基礎(chǔ)的編程語(yǔ)言,你想要做軟件開(kāi)發(fā),成為核心程序員的話,學(xué)習(xí)C/C++的話筆者有一個(gè)C/C++的編程倆千人羣(Q艘索:C/C++編程學(xué)習(xí)13群)你如果感覺(jué)自學(xué)C/C++語(yǔ)言有困難的話,有興趣學(xué)習(xí)或者了解一下C/C++編程的小伙伴就可以進(jìn)來(lái)交流。

總結(jié)

以上是生活随笔為你收集整理的c 包含其他文件_C/C++编程笔记:C/C++的编译和链接,计算机专业大学生必备知识...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。