認(rèn)識(shí)編譯器和C/C++編譯

一. 編譯器

編譯器也是一種程序渔肩,其作用是將一種語(yǔ)言翻譯為另一種語(yǔ)言周偎,通常是將高級(jí)語(yǔ)言翻譯為低級(jí)語(yǔ)言,或者說(shuō)是將源代碼翻譯成能被計(jì)算機(jī)或虛擬機(jī)執(zhí)行的目標(biāo)代碼吧兔。

編譯器的主要工作流程是:源代碼-預(yù)處理器-編譯器-目標(biāo)代碼-鏈接器-可執(zhí)行文件

另一個(gè)角度的工作流程:詞法分析-語(yǔ)法分析-語(yǔ)義分析-中間代碼生成-代碼優(yōu)化-目標(biāo)代碼生成-目標(biāo)代碼優(yōu)化

編譯器的種類(lèi)

“本地”編譯器

用來(lái)生成與編譯器本身所在環(huán)境操作系統(tǒng)(平臺(tái))相同的環(huán)境運(yùn)行的目標(biāo)代碼的編譯器叫“本地”編譯器。

“交叉”編譯器

生成用來(lái)在其他平臺(tái)上運(yùn)行的目標(biāo)代碼伺通,這種編譯器叫做“交叉”編譯器。這個(gè)過(guò)程也叫交叉編譯吴藻。

例如:在 Mac 上編譯能在 Android 上運(yùn)行的 so 弓柱, 這個(gè)過(guò)程就屬于交叉編譯。

編譯器的前后端

以中間代碼生成步驟為中心劃分:

  • 與源語(yǔ)言有關(guān)航罗,與目標(biāo)語(yǔ)言無(wú)關(guān)的部分叫做編譯器前端
  • 和目標(biāo)語(yǔ)言有關(guān)粥血,和源語(yǔ)言無(wú)關(guān)的部分叫做編譯器后端

將編譯器分為前端和后端酿箭,對(duì)編譯技術(shù)的起到了一定作用缭嫡。

二. GNU & GCC & Clang & llvm

1. GNU

GNU, Gnu's Not Unix 的縮寫(xiě)。由于一開(kāi)始 Unix 系統(tǒng)是商業(yè)收費(fèi)的耕突,理查德·斯托曼提出 GNU 計(jì)劃讥耗,希望發(fā)展出一套完整的開(kāi)放源代碼操作系統(tǒng)來(lái)取代 Unix古程,名為 GNU 蔼卡。

1989 年,GNU 項(xiàng)目中編輯器挣磨、編譯器雇逞、shell 等都已完成,唯獨(dú)缺了操作系統(tǒng)核心茁裙,所以開(kāi)始正式發(fā)展 Hurd 來(lái)作為 GNU 計(jì)劃的操作系統(tǒng)塘砸。

1991 年,Linux 出現(xiàn)晤锥, GNU 項(xiàng)目的軟件可在 Linux 上運(yùn)行掉蔬。

1992 年廊宪,Linux 和 GNU 結(jié)合,形成完全自由的操作系統(tǒng)箭启,稱(chēng)為 GNU/Linux 簡(jiǎn)稱(chēng) Linux 。此時(shí) Hurd 還沒(méi)完善蛉迹,被拋棄傅寡。

2. GCC

gcc, GNU C Compiler 的縮寫(xiě),是 GNU 項(xiàng)目的編譯器部分北救,也是類(lèi) Unix 和 Mac OS X 操作系統(tǒng)的標(biāo)準(zhǔn)編譯器荐操。

gcc 原本只處理 C 語(yǔ)言,后來(lái)也發(fā)展成可處理 Object-c珍策、Java 托启、C++。

g++

gcc 和 g++ 都是 GNU 的編譯器膛壹。他們的區(qū)別如下:

  • 對(duì)于 .c 驾中,gcc 把它當(dāng)作 C 程序,而 g++ 當(dāng)作 C++ 程序模聋;對(duì)于 .cpp , gcc 和 g++ 都會(huì)當(dāng)作 c++ 程序肩民。

對(duì)于 .cpp 的編譯鏈接
gcc 和 g++ 都可以編譯,而鏈接可以用 g++ 或者gcc -lstdc++链方。因?yàn)?gcc 命令不能自動(dòng)和 C++ 程序使用的庫(kù)聯(lián)接持痰,所以通常使用 -lstdc++ 來(lái)完成聯(lián)接。

3. Clang

Clang 是一個(gè) C祟蚀、C++工窍、Objective-C 和 Objective-C++ 編程語(yǔ)言的編譯器前端。它采用了底層虛擬機(jī)(LLVM)作為其后端前酿。這個(gè)軟件項(xiàng)目是由蘋(píng)果發(fā)起的患雏,目標(biāo)是替代 GNU 的 gcc 編譯器套裝。

因?yàn)?gcc 的編譯器慢慢無(wú)法滿(mǎn)足蘋(píng)果的需求罢维,因此淹仑,蘋(píng)果開(kāi)發(fā)了 Clang 與LLVM來(lái)完全取代 gcc,Xcode4 之后肺孵,蘋(píng)果的默認(rèn)編譯器已經(jīng)是 Clang/LLVM 匀借。Clang 作為編譯器前端,LLVM 作為編譯器后端平窘。

4. MinGw

MinGw 是 Minimalist GNU for Windows 的縮寫(xiě)吓肋。它是一個(gè)可自由使用和自由發(fā)布的 Windows 特定頭文件和使用 GNU 工具集導(dǎo)入庫(kù)的集合,允許在 Windows 平臺(tái)生成本地的 Windows 程序而不需要第三方 C 運(yùn)行時(shí)(C Runtime)庫(kù)瑰艘。

三. C/C++ 編譯過(guò)程

C/C++ 編譯過(guò)程可以分為四個(gè)步驟:

  • 預(yù)處理
  • 編譯
  • 匯編
  • 鏈接

1.預(yù)處理

預(yù)處理是處理文件中的預(yù)處理命令是鬼,通常是 # 開(kāi)頭肤舞,預(yù)處理通常包含如下步驟:

  • 替換宏定義 #define
  • 處理?xiàng)l件預(yù)編譯指令如 #if
  • 處理 #include 指令,將需要包含的文件遞歸包含進(jìn)來(lái)
  • 等等

可以使用 -E 命令執(zhí)行預(yù)處理操作屑咳,-o 表示生成的文件萨赁,最終生成 .i 文件

gcc -E -o test.i test.c


例如:有 test.h test.c 文件

>>test.h
int func(int a,int b) {
    return a + b;
}

>>test.c 

#include "test.h"
#define A 1
#define B 2
int main() {
    
    int c = func(A,B);
}

執(zhí)行 gcc -E -o test.i test.c

>> 生成的 test.i

# 1 "test.c"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 363 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "test.c" 2

# 1 "./test.h" 1


int func(int a,int b) {
    return a + b;
}
# 3 "test.c" 2


int main() {

    int c = func(1,2);
}

2. 編譯

編譯的過(guò)程是將經(jīng)過(guò)處理之后的程序轉(zhuǎn)換成特定匯編語(yǔ)言代碼的過(guò)程,可以使用 -E 命令執(zhí)行編譯操作兆龙,其表示讓編譯器編譯之后停止,不進(jìn)行后續(xù)步驟敲董。

gcc -S -o test.s test.c

>> 匯編代碼:

    .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 10, 15    sdk_version 10, 15, 4
    .globl  _func                   ## -- Begin function func
    .p2align    4, 0x90
_func:                                  ## @func
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    movl    %edi, -4(%rbp)
    movl    %esi, -8(%rbp)
    movl    -4(%rbp), %eax
    addl    -8(%rbp), %eax
    popq    %rbp
    retq
    .cfi_endproc
                                        ## -- End function
    .globl  _main                   ## -- Begin function main
    .p2align    4, 0x90
_main:                                  ## @main
    .cfi_startproc
## %bb.0:
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    movl    $1, %edi
    movl    $2, %esi
    callq   _func
    xorl    %ecx, %ecx
    movl    %eax, -4(%rbp)
    movl    %ecx, %eax
    addq    $16, %rsp
    popq    %rbp
    retq
    .cfi_endproc
                                        ## -- End function

.subsections_via_symbols

3.匯編

匯編是將上述匯編代碼轉(zhuǎn)換為機(jī)器碼紫皇,這一步產(chǎn)生的文件叫做目標(biāo)文件,是二進(jìn)制格式腋寨。每一個(gè)源文件都會(huì)產(chǎn)生一個(gè) .o 的目標(biāo)文件聪铺。

as test.s -o test.o

等價(jià)于

gcc –c test.c –o test.o

>> 這里就不貼

4.鏈接

鏈接過(guò)程是將目標(biāo)文件以及所需的庫(kù)文件,鏈接成最終的 .out 可執(zhí)行文件萄窜。鏈接程序的主要工作就是將有關(guān)的 .o 的目標(biāo)文件彼此相連接铃剔,使得所有的這些目標(biāo)文件成為一個(gè)能夠被操作系統(tǒng)裝入執(zhí)行的統(tǒng)一整體。

>> 執(zhí)行
gcc test.c

生成 a.out 的可執(zhí)行文件

在 mac 上執(zhí)行 ./a.out 可運(yùn)行文件

四. 靜態(tài)鏈接和動(dòng)態(tài)鏈接

靜態(tài)鏈接

靜態(tài)鏈接:在鏈接階段查刻,將匯編生成的目標(biāo)文件 .o 與引用到的庫(kù)一起鏈接打包進(jìn)可執(zhí)行文件中键兜。就是在編譯鏈接時(shí)直接將需要的執(zhí)行代碼拷貝到調(diào)用處,因此允許的時(shí)候存在多份內(nèi)存拷貝穗泵。

靜態(tài)鏈接庫(kù):一組目標(biāo)文件的的集合普气,即很多目標(biāo)文件經(jīng)過(guò)壓縮后打包形成一個(gè)文件 .a

靜態(tài)鏈接庫(kù)的特點(diǎn):

  • 靜態(tài)庫(kù)對(duì)函數(shù)庫(kù)的鏈接是放在編譯時(shí)期完成的
  • 程序在運(yùn)行的時(shí)候與函數(shù)庫(kù)無(wú)關(guān)
  • 浪費(fèi)內(nèi)存,多個(gè)地方調(diào)用某個(gè)函數(shù)就存在多次拷貝

動(dòng)態(tài)鏈接

就是在編譯的時(shí)候不直接拷貝可執(zhí)行的代碼佃延,而是通過(guò)記錄一系列符號(hào)和參數(shù)现诀,在程序運(yùn)行或加載時(shí)將這些信息傳遞給操作系統(tǒng),操作系統(tǒng)負(fù)責(zé)將需要的動(dòng)態(tài)庫(kù)加載到內(nèi)存中履肃。

然后程序在運(yùn)行到指定的代碼時(shí)仔沿,去共享執(zhí)行內(nèi)存中已經(jīng)加載的動(dòng)態(tài)庫(kù)可執(zhí)行代碼,最終達(dá)到運(yùn)行時(shí)連接的目的尺棋。

動(dòng)態(tài)鏈接庫(kù)的特點(diǎn):

  • 動(dòng)態(tài)庫(kù)把對(duì)一些庫(kù)函數(shù)的鏈接載入推遲到程序運(yùn)行的時(shí)期封锉。
  • 多個(gè)程序可以共享同一段代碼,而不需要在內(nèi)存上存儲(chǔ)多個(gè)拷貝陡鹃,
  • 缺點(diǎn)是由于是運(yùn)行時(shí)加載烘浦,可能會(huì)影響程序的前期執(zhí)行性能。
不同操作系統(tǒng)下編譯過(guò)程文件的后綴
系統(tǒng) 源文件 目標(biāo)文件 動(dòng)態(tài)鏈接庫(kù) 靜態(tài)鏈接庫(kù) 可執(zhí)行文件
windows .c/.cpp .obj .dll .lib .exe
Linux .c/.cpp .o .so .a .out/coff/elf (沒(méi)有后綴)
Mac OS X .c/.cpp .o .dylib .a .out/coff/elf (沒(méi)有后綴)
參考文章

編譯器
編譯器(GNU & GCC & clang & llvm)
C語(yǔ)言編譯過(guò)程詳解
Linux 中的動(dòng)態(tài)鏈接庫(kù)和靜態(tài)鏈接庫(kù)是干什么的

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末萍鲸,一起剝皮案震驚了整個(gè)濱河市闷叉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌脊阴,老刑警劉巖握侧,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚯瞧,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡品擎,警方通過(guò)查閱死者的電腦和手機(jī)埋合,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)萄传,“玉大人甚颂,你說(shuō)我怎么就攤上這事⌒懔猓” “怎么了振诬?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)衍菱。 經(jīng)常有香客問(wèn)我赶么,道長(zhǎng),這世上最難降的妖魔是什么脊串? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任辫呻,我火速辦了婚禮,結(jié)果婚禮上琼锋,老公的妹妹穿的比我還像新娘放闺。我一直安慰自己,他們只是感情好斩例,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布雄人。 她就那樣靜靜地躺著,像睡著了一般念赶。 火紅的嫁衣襯著肌膚如雪础钠。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,155評(píng)論 1 299
  • 那天叉谜,我揣著相機(jī)與錄音旗吁,去河邊找鬼。 笑死停局,一個(gè)胖子當(dāng)著我的面吹牛很钓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播董栽,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼码倦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了锭碳?” 一聲冷哼從身側(cè)響起袁稽,我...
    開(kāi)封第一講書(shū)人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎擒抛,沒(méi)想到半個(gè)月后推汽,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體补疑,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年歹撒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了莲组。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡暖夭,死狀恐怖锹杈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情迈着,我是刑警寧澤嬉橙,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站寥假,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏霞扬。R本人自食惡果不足惜糕韧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望喻圃。 院中可真熱鬧萤彩,春花似錦、人聲如沸斧拍。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)肆汹。三九已至愚墓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間昂勉,已是汗流浹背浪册。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留岗照,地道東北人村象。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像攒至,于是被迫代替她去往敵國(guó)和親厚者。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353