ヾ(????)?" 人總要為過(guò)去的懶惰而付出代價(jià)ヾ(????)?"
一、Linux編譯器-gcc/g++使用
1.1 背景知識(shí)
程序(文本)——>機(jī)器語(yǔ)言(二進(jìn)制)
- 預(yù)處理 (進(jìn)行宏替換)
- 編譯(生成匯編)
- 匯編(生成機(jī)器可識(shí)別代碼)
- 連接(生成可執(zhí)行文件或庫(kù)文件)
為什么計(jì)算機(jī)只認(rèn)識(shí)二進(jìn)制?
組成計(jì)算機(jī)的各種組件只認(rèn)識(shí)二進(jìn)制。
1.2 gcc如何完成
格式 gcc [選項(xiàng)] 要編譯的文件 [選項(xiàng)] [目標(biāo)文件]
C文件:gcc 文件->./a.out【g++ 文件->./a.out 】【因?yàn)閏++兼容C語(yǔ)言】
C++文件:g++文件->./a.out 【如果沒有g(shù)++編譯器,安裝gcc-c++即可】
gcc/g++ 文件1 -o 文件2 ——> 此時(shí)就不會(huì)生成a.out文件而是文件2
預(yù)處理(進(jìn)行宏替換)
- 預(yù)處理功能主要包括宏替換,頭文件展開,條件編譯,去注釋等。
- 預(yù)處理指令是以#號(hào)開頭的代碼行。
- 實(shí)例: gcc –E hello.c –o hello.i
- 選項(xiàng)“-E”,該選項(xiàng)的作用:從現(xiàn)在開始進(jìn)行程序的翻譯,gcc 在預(yù)處理結(jié)束后停止編譯過(guò)程。
- 選項(xiàng)“-o”是指目標(biāo)文件,“.i”文件為已經(jīng)過(guò)預(yù)處理的C原始程序
查看.i文件:首先vim hello.c 然后在末行模式輸入 vs hello.i 就可以進(jìn)入.i文件
編譯器內(nèi)部都必須通過(guò)一定方式來(lái)知道你包含的頭文件的所在路徑
預(yù)處理完之后,C語(yǔ)言代碼還是C語(yǔ)言代碼
編譯(生成匯編語(yǔ)言)
- 在這個(gè)階段中,gcc 首先要檢查代碼的規(guī)范性、是否有語(yǔ)法錯(cuò)誤等,以確定代碼的實(shí)際要做的工作,在檢查無(wú)誤后,gcc 把代碼翻譯成匯編語(yǔ)言。
- 用戶可以使用“-S”選項(xiàng)來(lái)進(jìn)行查看,該選項(xiàng)只進(jìn)行編譯而不進(jìn)行匯編,生成匯編代碼。
- 實(shí)例: gcc –S hello.i –o hello.s【也可以直接從.c文件開始翻譯到.s文件】
匯編(生成機(jī)器可識(shí)別代碼)
- 匯編階段是把編譯階段生成的“.s”文件【匯編語(yǔ)言】轉(zhuǎn)成目標(biāo)文件【可重定向二進(jìn)制文件.o/.obj】
- “-c”就可看到匯編代碼已轉(zhuǎn)化為“.o”的二進(jìn)制目標(biāo)文件
- 實(shí)例: gcc –c hello.s –o hello.o
【所有的包含頭文件的操作,本質(zhì)上是想使用頭文件所聲明的方法!例如:輸入輸出接口等】
以上操作,僅僅編譯了自己寫的代碼【僅僅這個(gè)文件是沒有辦法進(jìn)行運(yùn)行/.hello.o】
我們代碼中所需要的printf在哪里?在C標(biāo)準(zhǔn)庫(kù)中。
我們代碼中使用了printf,如何和目標(biāo)的printf產(chǎn)生聯(lián)系?【鏈接的過(guò)程】
【ESc】【iso】
鏈接(生成可執(zhí)行文件或庫(kù)文件)
- 在成功編譯之后,就進(jìn)入了鏈接階段。
- 實(shí)例: gcc hello.o –o hello
【這一步就有了鏈接的過(guò)程,就形成了可執(zhí)行文件】
ldd 可執(zhí)行文件【此時(shí)就可以看到所需要的庫(kù)】
頭文件:給我們提供了可以使用的方法,所有的開發(fā)環(huán)境,具有語(yǔ)法提示,本質(zhì)上是頭文件幫我們搜索的。【類似于我們平常寫代碼的頭文件】
庫(kù)文件:給我們提供了可以使用的方法的實(shí)現(xiàn),以供鏈接,形成我們自己的可執(zhí)行程序?!绢愃朴谖覀兤匠懙?c/.cpp文件】
1.3 函數(shù)庫(kù)
在這里涉及到一個(gè)重要的概念:函數(shù)庫(kù)
- 我們的C程序中,并沒有定義“printf”的函數(shù)實(shí)現(xiàn),且在預(yù)編譯中包含的“stdio.h”中也只有該函數(shù)的聲明,而沒有定義函數(shù)的實(shí)現(xiàn),那么,是在哪里實(shí)“printf”函數(shù)的呢?
答案:系統(tǒng)把這些函數(shù)實(shí)現(xiàn)都被做到名為 libc.so.6 的庫(kù)文件中去了,在沒有特別指定時(shí),gcc 會(huì)到系統(tǒng)默認(rèn)的搜索路徑“/usr/lib”下進(jìn)行查找,也就是鏈接到 libc.so.6 庫(kù)函數(shù)中去,這樣就能實(shí)現(xiàn)函數(shù)“printf”了,而這也就是鏈接的作用
函數(shù)庫(kù)一般分為靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)兩種
- 靜態(tài)庫(kù)是指編譯鏈接時(shí)【靜態(tài)鏈接】,把庫(kù)文件的代碼全部**加入到可執(zhí)行文件中**,因此生成的文件比較大,但在運(yùn)行時(shí)也就不再需要庫(kù)文件了。其后綴名一般為linux“.a”windows “.lib”
- 動(dòng)態(tài)庫(kù)與之相反,在編譯鏈接時(shí)【動(dòng)態(tài)鏈接】并沒有把庫(kù)文件的代碼加入到可執(zhí)行文件中,而是在程序執(zhí)行時(shí)由運(yùn)行時(shí)鏈接文件加載庫(kù),這樣可以節(jié)省系統(tǒng)的開銷。動(dòng)態(tài)庫(kù)一般**后綴名為linux“.so”windows".dll",**如前面所述的 libc.so.6 就是動(dòng)態(tài)庫(kù)。gcc 在編譯時(shí)默認(rèn)使用動(dòng)態(tài)庫(kù)。完成了鏈接之后,gcc 就可以生成可執(zhí)行文件,如下所示。 gcc hello.o –o hello
- gcc默認(rèn)生成的二進(jìn)制程序,是動(dòng)態(tài)鏈接的,這點(diǎn)可以通過(guò) file 命令驗(yàn)證。file 鏈接后的可執(zhí)行文件可以查看可執(zhí)行文件的構(gòu)成【默認(rèn)情況下,形成的可執(zhí)行文件是動(dòng)態(tài)鏈接的】
- gcc 文件 -o 可執(zhí)行文件 【動(dòng)態(tài)鏈接】 gcc 文件 -o 可執(zhí)行文件 -static 【靜態(tài)鏈接】【靜態(tài)鏈接的可執(zhí)行文件是非常大的,所以我們是用默認(rèn)的動(dòng)態(tài)鏈接】
- 靜態(tài)庫(kù)編譯軟件包:yum install glibc-static 【C語(yǔ)言】
yum install libstdc++ -static【C++】
靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)優(yōu)缺點(diǎn):
- 動(dòng)態(tài)鏈接庫(kù):優(yōu)點(diǎn):大家共享一個(gè)庫(kù),可以節(jié)省資源 缺點(diǎn):如果庫(kù)缺失,會(huì)導(dǎo)致幾乎所有程序失效
- 靜態(tài)鏈接庫(kù):優(yōu)點(diǎn):不依賴任何庫(kù),程序可以獨(dú)立執(zhí)行 缺點(diǎn):浪費(fèi)資源
1.4 gcc選項(xiàng)
- -E 只激活預(yù)處理,這個(gè)不生成文件,你需要把它重定向到一個(gè)輸出文件里面
- -S 編譯到匯編語(yǔ)言不進(jìn)行匯編和鏈接
- -c 編譯到目標(biāo)代碼
- -o 文件輸出到 文件
- -static 此選項(xiàng)對(duì)生成的文件采用靜態(tài)鏈接
- -g 生成調(diào)試信息。GNU 調(diào)試器可利用該信息。
- -shared 此選項(xiàng)將盡量使用動(dòng)態(tài)庫(kù),所以生成文件比較小,但是需要系統(tǒng)由動(dòng)態(tài)庫(kù).
- -O0
- -O1
- -O2
- -O3 編譯器的優(yōu)化選項(xiàng)的4個(gè)級(jí)別,-O0表示沒有優(yōu)化,-O1為缺省值,-O3優(yōu)化級(jí)別最高
- -w 不生成任何警告信息。
- -Wall 生成所有警告信息。
gcc選項(xiàng)技巧
- ESc,iso
二、linux調(diào)試器-gdb使用
2.1 背景
- 程序的發(fā)布方式有兩種,debug模式和release模式
- Linux gcc/g++出來(lái)的二進(jìn)制程序,默認(rèn)是release模式【默認(rèn)生成的可執(zhí)行文件,是無(wú)法調(diào)試的。-g】【debug才能調(diào)試】
- 要使用gdb調(diào)試,必須在源代碼生成二進(jìn)制程序的時(shí)候, 加上 -g 選項(xiàng) 【gcc 文件 -o 可執(zhí)行文件 -g】【調(diào)試的可執(zhí)行文件體積會(huì)大一點(diǎn),因?yàn)檫€有調(diào)試信息】
2.2 開始使用
gdb 可執(zhí)行文件
退出: ctrl + d 或 quit
- 當(dāng)編譯器不支持C99,可以:gcc 文件 -o 可執(zhí)行文件 -std=C99
- readelf -S 可執(zhí)行文件 可以看到調(diào)試信息
- readelf -S 可執(zhí)行文件 | grep debug【注意這里生成的是可執(zhí)行文件是debug的】 可以看到debug的調(diào)試信息
調(diào)試命令:
-
l 顯示代碼
-
(list 或 l) 行號(hào):顯示源代碼,接著上次的位置往下列,每次列10行。
-
(list/l )函數(shù)名:列出某個(gè)函數(shù)的源代碼。
-
r或run:運(yùn)行程序?!緮帱c(diǎn)停止,c ,到達(dá)下一個(gè)斷點(diǎn)】
-
n 或 next:?jiǎn)螚l執(zhí)行。【逐過(guò)程】
-
s 或step:進(jìn)入函數(shù)調(diào)用 【逐語(yǔ)句】
-
break (b) 行號(hào):在某一行設(shè)置斷點(diǎn)
-
break 函數(shù)名:在某個(gè)函數(shù)開頭設(shè)置斷點(diǎn)
-
info break(b) :查看斷點(diǎn)信息。
-
finish:執(zhí)行到當(dāng)前函數(shù),然后停下來(lái)等待命令
-
print§:打印表達(dá)式的值,通過(guò)表達(dá)式可以修改變量的值或者調(diào)用函數(shù)
-
p 變量:打印變量值。
-
set var:修改變量的值
-
continue(或c):從當(dāng)前位置開始連續(xù)而非單步執(zhí)行程序【斷點(diǎn)到斷點(diǎn)】
-
run(或r):從開始連續(xù)而非單步執(zhí)行程序
-
delete breakpoints:刪除所有斷點(diǎn)
-
delete breakpoints n(d 序號(hào)【序號(hào)可以用info b 查看】):刪除序號(hào)為n的斷點(diǎn)
-
disable breakpoints:禁用斷點(diǎn)
-
enable breakpoints:?jiǎn)⒂脭帱c(diǎn)
-
info(或i) breakpoints(info b):參看當(dāng)前設(shè)置了哪些斷點(diǎn)
-
display 變量名:(常顯示)跟蹤查看一個(gè)變量,每次停下來(lái)都顯示它的值
-
undisplay 序號(hào):(取消常顯示)取消對(duì)先前設(shè)置的那些變量的跟蹤
-
until X行號(hào):跳至X行
-
breaktrace(或bt):查看各級(jí)函數(shù)調(diào)用及參數(shù)
-
info(i) locals:查看當(dāng)前棧幀局部變量的值
-
quit:退出gdb
-
回車 可以顯示上一次gdb執(zhí)行的結(jié)果文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-667780.html
總結(jié)
以上就是今天要講的內(nèi)容,本文詳細(xì)地介紹了Linux編譯器-gcc/g++的使用、linux調(diào)試器-gdb的使用,希望給友友們帶來(lái)幫助!文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-667780.html
到了這里,關(guān)于【linux】2 Linux編譯器-gcc/g++和Linux調(diào)試器-gdb的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!