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

一. 編譯器

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

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

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

編譯器的種類

“本地”編譯器

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

“交叉”編譯器

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

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

編譯器的前后端

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

  • 與源語(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 的縮寫。由于一開始 Unix 系統(tǒng)是商業(yè)收費(fèi)的,理查德·斯托曼提出 GNU 計(jì)劃,希望發(fā)展出一套完整的開放源代碼操作系統(tǒng)來(lái)取代 Unix,名為 GNU 。

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

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

1992 年,Linux 和 GNU 結(jié)合,形成完全自由的操作系統(tǒng),稱為 GNU/Linux 簡(jiǎn)稱 Linux 。此時(shí) Hurd 還沒完善,被拋棄。

2. GCC

gcc, GNU C Compiler 的縮寫,是 GNU 項(xiàng)目的編譯器部分,也是類 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)目是由蘋果發(fā)起的,目標(biāo)是替代 GNU 的 gcc 編譯器套裝。

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

4. MinGw

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

三. C/C++ 編譯過程

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

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

1.預(yù)處理

預(yù)處理是處理文件中的預(yù)處理命令,通常是 # 開頭,預(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. 編譯

編譯的過程是將經(jīng)過處理之后的程序轉(zhuǎn)換成特定匯編語(yǔ)言代碼的過程,可以使用 -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.鏈接

鏈接過程是將目標(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)過壓縮后打包形成一個(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í)行的代碼,而是通過記錄一系列符號(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)下編譯過程文件的后綴
系統(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 (沒有后綴)
Mac OS X .c/.cpp .o .dylib .a .out/coff/elf (沒有后綴)
參考文章

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容