??博客主頁:小王又困了
??系列專欄:Linux
??人之為學(xué),不日近則日退?
??感謝大家點(diǎn)贊??收藏?評論??
目錄
一、快速認(rèn)識gcc/g++
?二、預(yù)處理
??1.1頭文件展開?
??1.2條件編譯
二、編譯
三、匯編
四、鏈接
??4.1庫的概念
??4.2庫的特點(diǎn)
??4.3庫的分類
??4.4動態(tài)鏈接
??4.5靜態(tài)鏈接
???前言:
? ? 在前面的文章中我們學(xué)會了vim的用法,可以寫一些代碼,要想讓我們的代碼運(yùn)行起來,還需要我們學(xué)會編譯工具gcc、g++的使用。C語言既可以使用gcc,也可以使用g++;C++只能使用g++,它們的使用形式是相同的,今天以gcc為主,介紹它們的使用方法,帶大家快速上手。
一、快速認(rèn)識gcc/g++
? ? ?當(dāng)我們寫完一段代碼,想要編譯時(shí)可以在命令行輸入:gcc code.c,會默認(rèn)形成a.out的可執(zhí)行程序。
在輸入./a.out,程序就可以執(zhí)行起來了。
? ? ?當(dāng)我們不想形成默認(rèn)的可執(zhí)行,想讓它形成指定名稱的可執(zhí)行,可以輸入:gcc code.c -o mycode 或 gcc -o mycode code.c。
編譯主要分為預(yù)處理、編譯、匯編、鏈接四個過程,我們將詳細(xì)講解這四個過程,帶大家學(xué)會gcc的使用。
?二、預(yù)處理
? ? ?此階段處理以 .c 或 .cpp 為擴(kuò)展名的源文件,并執(zhí)行預(yù)處理指令。預(yù)處理器的主要任務(wù)是頭文件展開、條件編譯、展開宏定義、移除注釋等。預(yù)處理指令都是以#開頭的代碼行。
- 指令:gcc -E code.c -o code.i
- -E:從現(xiàn)在開始進(jìn)行程序的翻譯過程,當(dāng)預(yù)處理做完的時(shí)候就停止
- -o:指目標(biāo)文件,將當(dāng)前編譯結(jié)果寫入到code.i文件中?
- ?.i?文件為經(jīng)過預(yù)處理的C語言程序(還是C語言)
??1.1頭文件展開?
? ? ?頭文件展開,就是在預(yù)處理的時(shí)候,將頭文件拷貝到引用它的源文件中。通過上圖我們可以看到,原本14行的代碼經(jīng)過預(yù)編譯變成了850行。多出的這么多代碼,就是把stdio.h文件中的內(nèi)容插入到當(dāng)前源文件中。/usr/include/目錄是Linux下gcc/g++頭文件的默認(rèn)搜索路徑,該路徑下有許多和開發(fā)相關(guān)的頭文件。
頭文件的展開過程涉及到#include預(yù)處理指令。當(dāng)預(yù)處理器遇到#include指令時(shí),它會打開指定的頭文件并將其內(nèi)容插入到當(dāng)前源文件的位置。這個過程可以分為兩種類型的包含:
- 系統(tǒng)頭文件的包含:
使用尖括號
<>
包含系統(tǒng)頭文件,例如:#include <stdio.h>
預(yù)處理器會在系統(tǒng)頭文件目錄中查找并打開stdio.h文件,并將其內(nèi)容插入到當(dāng)前源文件中。
- ?用戶頭文件的包含:
?使用雙引號?“ ”?包含用戶定義的頭文件,例如:
#include “test.h”
預(yù)處理器會在當(dāng)前源文件所在目錄以及指定的包含路徑中查找并打開test.h文件,并將其內(nèi)容插入到當(dāng)前源文件中。
??1.2條件編譯
? ? ?條件編譯就是處理?xiàng)l件編譯指令,如#if
、#ifdef
、#ifndef
、#else
、#elif
、#endif
等。根據(jù)條件判斷是否編譯特定代碼塊。例如:
#ifdef identifier
// 代碼塊 A
#else
// 代碼塊 B
#endif
如果已經(jīng)定義了標(biāo)識符identifier
,則編譯?// 代碼塊 A
?部分,否則編譯?// 代碼塊 B
?部分。
? ? ?條件編譯最重要的意義就是對頭文件的保護(hù),防止頭文件被重復(fù)包含。
#ifndef HEADER_FILE #define HEADER_FILE // 頭文件內(nèi)容 #endif
在展開頭文件時(shí),預(yù)處理器會繼續(xù)遞歸地處理被包含的頭文件。這意味著如果一個頭文件包含了另一個頭文件,那么這個被包含的頭文件也會被展開,以此類推,直到所有的頭文件都被插入到源文件中。我們使用上面這段條件編譯的代碼就可以避免這種情況,如果沒有定義HEADER_FILE,就執(zhí)行下面的代碼;如果定義了,就不會執(zhí)行了。
??條件編譯的主要用途包括:?
-
平臺特定代碼: 通過條件編譯,可以根據(jù)不同的操作系統(tǒng)或硬件平臺編寫特定的代碼。
-
調(diào)試和發(fā)布版本: 可以使用條件編譯來在調(diào)試版本和發(fā)布版本之間切換代碼。
-
特定功能的開關(guān): 通過條件編譯,可以選擇性地包含或排除某些功能,以滿足特定的編譯需求。
-
配置選項(xiàng): 根據(jù)不同的配置選項(xiàng)選擇性地包含或排除代碼,以適應(yīng)不同的編譯環(huán)境。
二、編譯
? ? ?在這個階段,預(yù)處理后的源代碼(通常是.i
文件)被翻譯成匯編語言。gcc 首先要檢查代碼的規(guī)范性、是否有語法錯誤等,以確定代碼的實(shí)際要做的工作,在檢查無誤后,gcc 把代碼翻譯成匯編語言。生成的匯編代碼描述了程序的控制流、數(shù)據(jù)等信息。
- 指令:gcc -S?code.i?-o code.s
- -S:從現(xiàn)在開始進(jìn)行程序的翻譯過程,當(dāng)編譯工作做完的時(shí)候就停止
三、匯編
? ? ?在這個階段,匯編器將匯編代碼(通常是.s
文件)翻譯成機(jī)器碼或可重定位的機(jī)器碼。它將匯編代碼轉(zhuǎn)換成二進(jìn)制目標(biāo)文件,其中包含特定于處理器體系結(jié)構(gòu)的指令。這個二進(jìn)制文件也被叫做可重定位目標(biāo)二進(jìn)制文件,簡稱目標(biāo)文件。但是它不能被執(zhí)行。
- ?指令:gcc -c?code.s?-o code.o
- -c:從現(xiàn)在開始進(jìn)行程序的翻譯過程,當(dāng)匯編工作做完的時(shí)候就停止
??目標(biāo)文件為什么不能執(zhí)行?
? ? ?目標(biāo)文件通常沒有定義程序的入口點(diǎn),即程序的起始地址??蓤?zhí)行文件需要一個明確定義的入口點(diǎn),從這個點(diǎn)開始執(zhí)行程序。單獨(dú)的目標(biāo)文件可能包含了未解決的符號引用,無法獨(dú)立執(zhí)行。可執(zhí)行文件需要在操作系統(tǒng)上運(yùn)行,而操作系統(tǒng)提供了運(yùn)行時(shí)支持,包括內(nèi)存管理、文件操作、進(jìn)程調(diào)度等。沒有這些支持,程序很難在操作系統(tǒng)上正確運(yùn)行。所以,我們還要通過鏈接來解決這些問題,讓目標(biāo)文件與其他目標(biāo)文件或庫文件進(jìn)行鏈接,形成最終的可執(zhí)行文件。
四、鏈接
? ? ?在這個階段,鏈接器將一個或多個目標(biāo)文件(通常是.o
文件)與所需的庫文件結(jié)合,創(chuàng)建可執(zhí)行文件。鏈接的主要任務(wù)包括符號解析、地址解析、重定位等,以確保所有部分正確地組合在一起。
- 指令:gcc? code.o?-o mycode
??4.1庫的概念
? ? ?庫通常指的是包含可重用代碼和資源的集合,目的是為了幫助開發(fā)者完成特定任務(wù)。庫可以包含函數(shù)、類、變量、子例程等,提供了一組API(應(yīng)用程序接口)或者工具,使得開發(fā)者能夠更輕松地完成常見的編程任務(wù),而無需從頭開始編寫所有的代碼。
? ? ?我們的C程序中,并沒有定義printf的函數(shù)實(shí)現(xiàn),且在預(yù)編譯中包含的“stdio.h”中也只有該函數(shù)的聲明,而沒有定義函數(shù)的實(shí)現(xiàn),那么,是在哪里實(shí)現(xiàn)printf函數(shù)的呢? 答案是:系統(tǒng)把這些函數(shù)實(shí)現(xiàn)都被做到名為?libc.so.6 的庫文件中去了,在沒有特別指定時(shí),gcc會到系統(tǒng)默認(rèn)的搜索路徑/usr/lib下進(jìn)行查找,會默認(rèn)找到C的標(biāo)準(zhǔn)庫,它會把我們寫的源代碼經(jīng)過編譯得到的目標(biāo)文件與庫文件進(jìn)行鏈接,也就是鏈接到 libc.so.6 庫函數(shù)中去,這樣就能實(shí)現(xiàn)函數(shù)printf了,而這也就是鏈接的作用。
- ?libc.so.6 就是C語言的標(biāo)準(zhǔn)庫。?
??4.2庫的特點(diǎn)
可重用性: 庫中的代碼可以在不同的程序中被重復(fù)使用,從而減少了代碼的冗余,提高了開發(fā)效率。
封裝性: 庫提供了一個封裝的接口,隱藏了內(nèi)部實(shí)現(xiàn)的細(xì)節(jié),使得開發(fā)者可以專注于使用功能而不必關(guān)心底層的實(shí)現(xiàn)。
模塊化: 庫通常被組織成模塊,每個模塊負(fù)責(zé)一個特定的功能。這種模塊化的設(shè)計(jì)有助于提高代碼的可維護(hù)性和可擴(kuò)展性。
標(biāo)準(zhǔn)化: 一些庫成為了編程的標(biāo)準(zhǔn),被廣泛接受和使用。這樣的庫通常提供了一些通用的解決方案,被廣泛認(rèn)可并得到社區(qū)的支持。
??4.3庫的分類
? ? ?庫分為兩類:動態(tài)庫和靜態(tài)庫。其中Linux環(huán)境下,動態(tài)庫的后綴是.so
,靜態(tài)庫的后綴是.a
。在Windows環(huán)境下,動態(tài)庫的后綴是.dll
,靜態(tài)庫的后綴是.lib
。所有的庫文件,都遵守相同的命名規(guī)則,即:libname.后綴.xxx
。
-
靜態(tài)庫(Static Library): 在編譯時(shí)被鏈接到程序中,程序在運(yùn)行前就包含了庫的代碼。這意味著庫的代碼被復(fù)制到了程序的可執(zhí)行文件中。
-
動態(tài)庫(Dynamic Library): 在運(yùn)行時(shí)被加載到內(nèi)存中,程序在運(yùn)行時(shí)可以調(diào)用庫的函數(shù)。這樣可以減小程序的大小,因?yàn)槎鄠€程序可以共享同一個庫的實(shí)例。
?常見的庫包括標(biāo)準(zhǔn)庫(如C標(biāo)準(zhǔn)庫、C++標(biāo)準(zhǔn)庫)、圖形界面庫(如Qt、GTK+)、數(shù)學(xué)庫(如NumPy)、網(wǎng)絡(luò)庫(如libcurl)、以及許多其他領(lǐng)域的專用庫。
??4.4動態(tài)鏈接
? ? ?動態(tài)鏈接是一種在程序運(yùn)行時(shí)將代碼和數(shù)據(jù)庫鏈接到程序中的技術(shù)。把庫中要用到的庫函數(shù)的地址寫到在我們代碼中調(diào)用這個函數(shù)的地方,就是動態(tài)鏈接。
-
指令ldd 可執(zhí)行程序
,可以查看一個可執(zhí)行程序所依賴的動態(tài)庫。
gcc的默認(rèn)行為是動態(tài)鏈接?
??動態(tài)鏈接的優(yōu)點(diǎn):
- 節(jié)省內(nèi)存:?多個程序可以共享同一份庫的實(shí)例,從而節(jié)省內(nèi)存。
- 易于更新:?更新庫時(shí),不需要重新編譯所有依賴于該庫的程序。只需替換庫的新版本即可。
- 靈活性:?可以在程序運(yùn)行時(shí)動態(tài)加載和卸載庫,使得程序更加靈活。
???動態(tài)鏈接的缺點(diǎn):
- 依賴性:對庫的依賴性強(qiáng) 一旦庫丟失,所有使用這個庫的程序都無法運(yùn)行
??4.5靜態(tài)鏈接
? ? ?靜態(tài)鏈接是一種在程序編譯時(shí)將所有代碼和庫鏈接到一個獨(dú)立的可執(zhí)行文件的過程。這意味著在程序運(yùn)行之前,所有的代碼和庫已經(jīng)被合并成一個單獨(dú)的可執(zhí)行文件。把庫中的代碼拷貝到我們的可執(zhí)行程序中,就是靜態(tài)鏈接。
在Linux中默認(rèn)是沒有靜態(tài)庫的,需要我們自己安裝。
- sudo yum install -y glibc-static?
- gcc code.c -o mycode-static -static
- 其中 -static表示執(zhí)行靜態(tài)鏈接
??靜態(tài)鏈接的優(yōu)點(diǎn):
- 獨(dú)立性:?生成的可執(zhí)行文件是完全獨(dú)立的,不需要外部的依賴。這使得程序更容易分發(fā)和部署,因?yàn)橛脩糁恍枰粋€文件就可以運(yùn)行程序。
- 性能:?靜態(tài)鏈接的程序在運(yùn)行時(shí)無需進(jìn)行額外的庫加載,因此在一些情況下可能會稍微快于動態(tài)鏈接的程序。
??靜態(tài)鏈接的缺點(diǎn):文章來源:http://www.zghlxwxcb.cn/news/detail-752314.html
- 占用空間:?由于每個可執(zhí)行文件包含了所需的所有代碼和庫,因此靜態(tài)鏈接的程序通常比動態(tài)鏈接的程序更大。
- 更新困難:?如果庫被更新,需要重新編譯并重新分發(fā)整個可執(zhí)行文件,而不僅僅是替換庫文件。
本次的內(nèi)容到這里就結(jié)束啦。希望大家閱讀完可以有所收獲,同時(shí)也感謝各位讀者三連支持。文章有問題可以在評論區(qū)留言,博主一定認(rèn)真認(rèn)真修改,以后寫出更好的文章。你們的支持就是博主最大的動力。文章來源地址http://www.zghlxwxcb.cn/news/detail-752314.html
到了這里,關(guān)于『Linux升級路』基礎(chǔ)開發(fā)工具——gcc/g++篇的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!