C/C++ 從0到1系統(tǒng)精講 項(xiàng)目開(kāi)發(fā)綜合基礎(chǔ)K-春風(fēng)送暖入屠蘇
作為挪動(dòng)開(kāi)發(fā)你不能不理解的編譯流程
C/C++ 從0到1系統(tǒng)精講 項(xiàng)目開(kāi)發(fā)綜合基礎(chǔ)K
download:https://www.51xuebc.com/thread-543-1-1.html
閱讀本文,或許可以理解關(guān)于以下的幾個(gè)問(wèn)題: 1、編譯器是什么?為什么會(huì)有編譯器這樣一個(gè)東西? 2、編譯器做了哪些工作?整個(gè)編譯過(guò)程又是什么? 3、Apple的編譯器開(kāi)展進(jìn)程以及為什么會(huì)丟棄GCC換成自研的LLVM? 4、從編譯器角度看Swift與OC可以完成混編的底層邏輯
一、找個(gè)翻譯官,說(shuō)點(diǎn)計(jì)算機(jī)能懂的言語(yǔ)
說(shuō)點(diǎn)常識(shí),眾所周知,作為開(kāi)發(fā)者我們能看懂這樣的代碼:
int a = 10;
int b = 20;
int c = a + b;
而關(guān)于計(jì)算機(jī)貌似只能明白這樣的內(nèi)容:
注:運(yùn)用 od -tx1 /tmp/binary.bin 能夠依據(jù)需求輸出二進(jìn)制、八進(jìn)制或者十六進(jìn)制的內(nèi)容
這樣看的話,計(jì)算機(jī)除了曉得1與0的含義,其他的字符內(nèi)容完整不曉得。為了去給計(jì)算機(jī)下達(dá)我們需求的指令,我們又不得不得依照計(jì)算機(jī)可以懂得言語(yǔ)與其停止通訊交流,怎樣辦呢?我們貌似需求找一個(gè)翻譯,將我們的想要下達(dá)的指令內(nèi)容交給翻譯讓其成計(jì)算機(jī)可以辨認(rèn)的指令停止內(nèi)容傳達(dá),這樣計(jì)算機(jī)就能經(jīng)過(guò)翻譯來(lái)一步步執(zhí)行我們的指令動(dòng)作了,那這個(gè)翻譯其實(shí)就是我們經(jīng)常說(shuō)到的編譯器。
說(shuō)到編譯器呢?它的歷史還是很長(zhǎng)久的,早期的計(jì)算機(jī)軟件都是用匯編言語(yǔ)直接編寫(xiě)的,這種情況持續(xù)了數(shù)年。當(dāng)人們發(fā)現(xiàn)為不同類(lèi)型的中央處置器CPU編寫(xiě)可重用軟件的開(kāi)支要明顯高于編寫(xiě)編譯器時(shí),人們創(chuàng)造了高級(jí)編程言語(yǔ)。簡(jiǎn)單說(shuō)就是由于中央處置器CPU的差別,使得軟件的開(kāi)發(fā)本錢(qián)很高,我們要針對(duì)不同的CPU編寫(xiě)不同的匯編代碼,而且不同的CPU架構(gòu)呢相對(duì)應(yīng)的匯編的指令集也有差別。假如在匯編體系之上定義一套與匯編無(wú)關(guān)的編碼言語(yǔ),經(jīng)過(guò)對(duì)通用的這樣言語(yǔ)停止轉(zhuǎn)換,將其轉(zhuǎn)換成不同類(lèi)型的CPU的匯編指令,是不是就能處理不同CPU架構(gòu)適配的問(wèn)題呢?那其中的定義的通用編碼言語(yǔ)就是我們所說(shuō)的高級(jí)言語(yǔ),比方C/C++、Object-C、Swift、Java等等,而其中的匯編翻譯轉(zhuǎn)換工作呢則交由詳細(xì)的編譯器停止完成。
二、說(shuō)到編譯器當(dāng)然少不了Apple
關(guān)于Apple的編譯器,就不得不說(shuō)一下GCC與LLVM的相愛(ài)相殺了。由于編譯器觸及到從高級(jí)開(kāi)發(fā)言語(yǔ)到低級(jí)言語(yǔ)的轉(zhuǎn)換處置,復(fù)雜度自然不用多說(shuō)。我們都曉得Apple產(chǎn)品軟件的開(kāi)發(fā)言語(yǔ)是Objective-C,能夠以為是對(duì)C言語(yǔ)的擴(kuò)展。而C言語(yǔ)所運(yùn)用的編譯器則是大名鼎鼎的GCC,此時(shí)的GCC肯定是妥妥的大哥了,所以早些年為了不用要的資源投入,關(guān)于自家OC(Objective-C簡(jiǎn)稱(chēng)OC)編譯器的開(kāi)發(fā)索性直接拿大哥的代碼GCC停止二次開(kāi)發(fā)了,沒(méi)錯(cuò),從主干版本中拉個(gè)獨(dú)立分支搞起。這么看的話,Apple早期就曾經(jīng)開(kāi)端了降本增效了?
隨著OC言語(yǔ)的不時(shí)迭代開(kāi)展,言語(yǔ)特性也就愈來(lái)愈多,那編譯器的新特性才能支持當(dāng)然也得跟得上???但是C也在不時(shí)的迭代開(kāi)展,GCC編譯器的主干功用當(dāng)然也越來(lái)越多,OMG!單獨(dú)維護(hù)的OC編譯器版本對(duì)GCC主干的新功用并沒(méi)有很好的同步,關(guān)鍵在兼并功用的時(shí)分不可防止的呈現(xiàn)種種抵觸。為此,Apple曾屢次申請(qǐng)與GCC主干功用兼并同步,GCC乍一看都是OC 特性feature,跟C有毛線關(guān)系?所以關(guān)于兼并的優(yōu)先級(jí)總是排到最低,Apple也是沒(méi)有方法,結(jié)果只能是差別化的東西越來(lái)越多,編譯器的維護(hù)本錢(qián)也變得異常之高。
除了以上的問(wèn)題之外,GCC整體的架構(gòu)設(shè)計(jì)也是非模塊化的,那什么是模塊化呢?比方我們通常在系統(tǒng)設(shè)計(jì)的時(shí)分,會(huì)將各個(gè)系統(tǒng)的功用停止模塊化分割設(shè)計(jì),不同的模塊可以單獨(dú)為系統(tǒng)內(nèi)部提供不同的功用。同時(shí)呢,我們還能把這些模塊單獨(dú)抽離出來(lái)提供應(yīng)外部運(yùn)用,這就增大了系統(tǒng)的底層的靈敏度,簡(jiǎn)單說(shuō)就是可以直接運(yùn)用模塊化的接口才能。
所以Apple深知定制化的GCC編譯器將是后續(xù)言語(yǔ)迭代晉級(jí)的絆腳石,內(nèi)部也在不時(shí)的探究可以替代GCC的替代品。在編譯器的探究路上,這里不得不說(shuō)一下Apple的一位神級(jí)工程師 Chris Lattner(克里斯·拉特納),可能光說(shuō)名字的話可能沒(méi)有太多人曉得他,那假如要說(shuō)Swift言語(yǔ)的開(kāi)創(chuàng)人是不是就有所耳聞了?由于克里斯在大學(xué)期間對(duì)編譯器的細(xì)致的研討,發(fā)起了LLVM(Low Level Virtual Machine)項(xiàng)目對(duì)編譯的源代碼停止了整體的優(yōu)化。Apple將眼光放在了克里斯團(tuán)隊(duì)身上,同時(shí)直接顧用了他們團(tuán)隊(duì),當(dāng)然克里斯也沒(méi)有孤負(fù)眾望,在 Xcode從 3.1完成了llvm-gcc compiler,到 3.2完成了Clang 1.0, 再到4.0完成了Clang 2.0 ,后來(lái)在Mac OS X 10.6 開(kāi)端運(yùn)用LLVM的編譯技術(shù),到如今曾經(jīng)將LLVM開(kāi)展成為了Apple的中心編譯器。
三、LLVM編譯器的編譯過(guò)程與特性
關(guān)于傳統(tǒng)的編譯器,主要分為前端、優(yōu)化器和后端,援用一張通用的簡(jiǎn)約的編譯過(guò)程圖,如下:
簡(jiǎn)單來(lái)說(shuō),針關(guān)于源代碼翻譯成計(jì)算機(jī)底層代碼的過(guò)程中呢要閱歷三個(gè)階段:前端編譯、優(yōu)化器優(yōu)化、后端編譯。經(jīng)過(guò)前端編譯之后,針對(duì)編譯的產(chǎn)物停止優(yōu)化處置,最后經(jīng)過(guò)后端完成機(jī)器碼的生成。而關(guān)于LLVM編譯器來(lái)說(shuō),這里我們以O(shè)C的前端編譯器Clang為例,它擔(dān)任LLVM的前端的整體編譯流程(預(yù)處置、詞法剖析、語(yǔ)法剖析和語(yǔ)義剖析),生成中間產(chǎn)物L(fēng)LVMIR,最后由后端停止架構(gòu)處置生成目的代碼,如下圖:
能夠看出LLVM將編譯的前后端獨(dú)立分開(kāi)了,前端擔(dān)任不同言語(yǔ)的編譯操作,假如增加一個(gè)言語(yǔ)的編譯支持,只需求擴(kuò)展支持當(dāng)前言語(yǔ)的前端編譯支持(Clang擔(dān)任OC前端編譯、SwiftC擔(dān)任Swift前端編譯)即可,優(yōu)化器與后端編譯器整體均不用修正即可完成新增言語(yǔ)的支持。同理,關(guān)于后端,假如需求新增新的架構(gòu)設(shè)備的支持,只需求擴(kuò)展后端架構(gòu)對(duì)應(yīng)編譯器的支持即可完成新架構(gòu)設(shè)備的支持,這也是LLVM編譯器的優(yōu)點(diǎn)之一。
3.1、編譯器前端
在XCode中針關(guān)于OC與Swift的編譯有著不同的前端編譯器,OC采用Clang停止編譯,而Swift則采用SwiftC編譯器,兩種不同的編譯器前端在編譯之后,生成的中間產(chǎn)物都是LLVMIR。這也就解釋了關(guān)于高級(jí)言語(yǔ)Swift或者OC開(kāi)發(fā),哪怕是混編,在經(jīng)過(guò)各自的編譯器前端編譯之后,最終的編譯產(chǎn)物都是一樣的,所以選用哪種開(kāi)發(fā)言語(yǔ)關(guān)于最終生成的中間代碼IR都是通用的。關(guān)于Clang的整體編譯過(guò)程,如下圖所示:
預(yù)處置
經(jīng)過(guò)對(duì)源代碼中以“#”號(hào)開(kāi)頭如包含#include,宏定義制定#define等掃描。然后停止源代碼定義交換,停止頭文件內(nèi)容的展開(kāi)。經(jīng)過(guò)預(yù)處置器把源文件處置成.i文件。
詞法剖析
在詞法剖析完成之后會(huì)生成 token 產(chǎn)物,它是做什么的?這里不貼官方的解釋了,簡(jiǎn)單點(diǎn)說(shuō)就是對(duì)源代碼的原子切分,切分紅可以底層描繪的單個(gè)原子,就是所謂的token,至于token長(zhǎng)什么樣子?能夠經(jīng)過(guò) clang 的命令執(zhí)行編譯查看生成的原子內(nèi)容:
clang -fmodules -E -Xclang -dump-tokens xxx.m
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
appDelegateClassName = NSStringFromClass([AppDelegate class]);
int a = 0;
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
我們拿工程的main.m 做個(gè)測(cè)試,編譯生成的內(nèi)容如下:
注:假如遇到 main.m:8:9: fatal error: 'UIKit/UIKit.h' file not found 錯(cuò)誤,能夠加上系統(tǒng)根底庫(kù)途徑如下:
clang \
-fmodules \
-E \
-Xclang \
-dump-tokens \
-isysroot \
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk \
main.m
能夠發(fā)現(xiàn),計(jì)算機(jī)在停止源碼處置的時(shí)分,并不能像人一樣可以了解整個(gè)源碼內(nèi)容的含義。所以為了停止轉(zhuǎn)換,在停止源碼剖析的時(shí)分,將整體的內(nèi)容停止單詞切分,構(gòu)成原子為后續(xù)的語(yǔ)義剖析做準(zhǔn)備,整體的切分過(guò)程大致采用的是狀態(tài)機(jī)原理。
語(yǔ)法剖析
在完成詞法剖析之后,編譯器大致了解了每個(gè)源碼中的單詞的意義,但是關(guān)于單詞組合起來(lái)的語(yǔ)句內(nèi)容并不能了解。所以接下來(lái)需求對(duì)單詞組合起來(lái)的內(nèi)容停止辨認(rèn),也就是我們所說(shuō)的**語(yǔ)法剖析**。 語(yǔ)法剖析的原理有點(diǎn)模板匹配的意義,怎樣了解呢?就是我們常說(shuō)的語(yǔ)法規(guī)則,在編譯器中預(yù)置了相關(guān)言語(yǔ)的語(yǔ)法規(guī)則模板,假如匹配了相關(guān)的規(guī)則,則依照相關(guān)語(yǔ)法規(guī)則停止解析。舉個(gè)例子,比方我們?cè)贠C中寫(xiě)一個(gè)這樣的語(yǔ)句:
int a = 100;
這是一種通用的賦值語(yǔ)法格式,所以在編譯器停止語(yǔ)法剖析的時(shí)分,將其依照賦值語(yǔ)法的規(guī)則停止解析,如下:
經(jīng)過(guò)對(duì)原子token的組合解析,最終會(huì)生成了一個(gè)籠統(tǒng)語(yǔ)法樹(shù)(AST),AST籠統(tǒng)語(yǔ)法樹(shù)將源代碼轉(zhuǎn)換成樹(shù)狀的數(shù)據(jù)構(gòu)造,它描繪了源代碼的內(nèi)容含義以及內(nèi)容構(gòu)造,它的生成可以讓計(jì)算機(jī)更好的了解和處置中間產(chǎn)物。以XCode生成的默許項(xiàng)目的main.m內(nèi)容為例,在 clang 中我們照舊能夠查看詳細(xì)的籠統(tǒng)生成樹(shù)(AST)的樣子,能夠?qū)υ创a停止如下的編譯:
clang \
-isysroot \
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk \
-fmodules \
-fsyntax-only \
-Xclang \
-ast-dump \
main.m
編譯后的結(jié)果如下:
簡(jiǎn)單轉(zhuǎn)換一下樹(shù)形視圖,大致長(zhǎng)這樣:
能夠發(fā)現(xiàn),閱歷過(guò)語(yǔ)法剖析之后,源代碼轉(zhuǎn)換成了詳細(xì)的數(shù)據(jù)構(gòu)造,而數(shù)據(jù)構(gòu)造的整體生成是后續(xù)停止語(yǔ)義剖析生成中間代碼的根底前提。
語(yǔ)義剖析
在閱歷過(guò)語(yǔ)法剖析之后,編譯器會(huì)對(duì)語(yǔ)法剖析之后生成的籠統(tǒng)語(yǔ)法樹(shù)(AST)再次停止處置,需求留意的是編譯器并不會(huì)直接經(jīng)過(guò)AST編譯成目的代碼,主要緣由是由于編譯器將編譯過(guò)程拆分了前后端,而前后端的通訊的媒介就是IR,沒(méi)錯(cuò)就是之前提到過(guò)的LLVMIR這樣一個(gè)中間產(chǎn)物。該中間產(chǎn)物與言語(yǔ)無(wú)關(guān),同時(shí)與cpu的架構(gòu)也無(wú)關(guān),那么為什么要加上中間產(chǎn)物這個(gè)環(huán)節(jié),直接生成目的代碼難道不是更好嗎?我們都曉得cpu的不同架構(gòu)直接影響cpu的指令集,不同的指令集對(duì)應(yīng)不同的匯編指令,所以針關(guān)于不同的cpu架構(gòu)要對(duì)應(yīng)生成不同適配的匯編指令才干正常的運(yùn)轉(zhuǎn)到不同的cpu架構(gòu)的機(jī)器上。假如將前后端的編譯過(guò)程綁定死,那么就會(huì)招致每增加一個(gè)新的編譯前端,同時(shí)增加對(duì)一切cpu架構(gòu)的后端的支持(1對(duì)n的關(guān)系),同理,假如增加新的一個(gè)cpu架構(gòu)支持,編譯前端也需求統(tǒng)統(tǒng)再完成一遍,這個(gè)工作量是很反復(fù)以及繁瑣的。所以為了防止這樣的問(wèn)題,Apple對(duì)編譯器的前后端停止了拆分,用中間產(chǎn)物來(lái)停止前后端的邏輯適配。
關(guān)于語(yǔ)義剖析生成中間產(chǎn)物的過(guò)程,也能夠經(jīng)過(guò) Clang 的編譯命令查看,詳細(xì)如下:
# 生成擴(kuò)展為.ll的便于閱讀的文本格式
clang \
-isysroot \
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk \
-S \
-emit-llvm \
main.m \
-o \
main.ll
# 生成二進(jìn)制格式,擴(kuò)展為.bc
clang \
-isysroot \
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk \
-emit-llvm \
-c \
main.m \
-o \
main.bc
從編譯的產(chǎn)物來(lái)看,其中也包含了常見(jiàn)的內(nèi)存分配、所用到的標(biāo)識(shí)定義等內(nèi)容,能夠明顯的發(fā)現(xiàn)生成的中間產(chǎn)物曾經(jīng)沒(méi)有任何源代碼言語(yǔ)的影子了。同時(shí)我們會(huì)發(fā)現(xiàn)針關(guān)于中間代碼,存放器(%+數(shù)字)的運(yùn)用仿佛沒(méi)有個(gè)數(shù)限制,為什么呢?由于中間代碼只是將源代碼停止了中間代碼的描繪轉(zhuǎn)義,此時(shí)并沒(méi)有相關(guān)的目的架構(gòu)信息可供參考運(yùn)用,所以針關(guān)于變量的援用也僅僅是中間層的標(biāo)識(shí)。在后端編譯的過(guò)程中會(huì)將中間的這些存放器的援用再次停止指令的轉(zhuǎn)換,最終會(huì)生成對(duì)應(yīng)CPU架構(gòu)指令集的匯編代碼。
還記得XCode中的BitCode開(kāi)關(guān)選項(xiàng)嗎?它決議了編譯生成的中間產(chǎn)物IR能否需求保管,假如保管的話,會(huì)把當(dāng)前的中間產(chǎn)物插入到可執(zhí)行文件的數(shù)據(jù)段中,保存這些中間產(chǎn)物內(nèi)容又有什么作用呢?我們曉得在沒(méi)有保存中間產(chǎn)物之前,為了確保一切cpu架構(gòu)的機(jī)型可以正常裝置打出的裝置包,在打包的時(shí)分會(huì)把可以支持的一切cpu架構(gòu)的匯合停止兼并打包,生成一個(gè)Fat Binary,確保裝置包可以適配一切的機(jī)型,這樣會(huì)有一個(gè)問(wèn)題,比方ARM64架構(gòu)的機(jī)器在裝置的時(shí)分只需求ARM64的架構(gòu)二進(jìn)制文件即可,但是由于裝置包里兼容了一切的cpu架構(gòu),其他的架構(gòu)代碼實(shí)踐上基本沒(méi)有用到,這也就間接的招致了裝置包的體積變大。而蘋(píng)果在應(yīng)用分發(fā)的時(shí)分,是曉得目的機(jī)器的cpu架構(gòu)的,所以假如可以將中間的編譯產(chǎn)物交給AppStore后臺(tái),由Appstore后臺(tái)經(jīng)過(guò)編譯后端優(yōu)化生成目的機(jī)器的二進(jìn)制可執(zhí)行文件,去除無(wú)用的兼容架構(gòu)代碼,進(jìn)而縮減裝置包的體積大小。這也即是BitCode的呈現(xiàn)目的,為理解決編譯架構(gòu)冗余的問(wèn)題,同時(shí)也為APP的瘦身提供參考。
編譯器在停止語(yǔ)義剖析期間還有一個(gè)重要的過(guò)程叫做靜態(tài)剖析(Static Analysis),llvm官方文檔是這樣引見(jiàn)靜態(tài)剖析的:
The term "static analysis" is conflated, but here we use it to mean a collection of algorithms and techniques used to analyze source code in order to automatically find bugs. The idea is similar in spirit to compiler warnings (which can be useful for finding coding errors) but to take that idea a step further and find bugs that are traditionally found using run-time debugging techniques such as testing.?
Static analysis bug-finding tools have evolved over the last several decades from basic syntactic checkers to those that find deep bugs by reasoning about the semantics of code. The goal of the Clang Static Analyzer is to provide a industrial-quality static analysis framework for analyzing C, C++, and Objective-C programs that is freely available, extensible, and has a high quality of implementation.
靜態(tài)剖析它可以協(xié)助我們?cè)诰幾g期間自動(dòng)查找錯(cuò)誤,比起運(yùn)轉(zhuǎn)時(shí)的時(shí)分去找出錯(cuò)誤要更早一步,能夠用于剖析 C、C++ 和 Objective-C 程序。編譯器經(jīng)過(guò)靜態(tài)剖析根據(jù)AST中節(jié)點(diǎn)與節(jié)點(diǎn)之間的關(guān)系,找出有問(wèn)題的節(jié)點(diǎn)并拋出正告錯(cuò)誤,到達(dá)修正提示的目的。比方官方文檔中引見(jiàn)的內(nèi)存泄露的靜態(tài)剖析的案例:
除了官方的靜態(tài)剖析,我們常用的OCLint也是在編譯器生成AST籠統(tǒng)語(yǔ)法樹(shù)之后,對(duì)籠統(tǒng)語(yǔ)法樹(shù)停止遍歷剖析,到達(dá)校驗(yàn)標(biāo)準(zhǔn)的目的,總結(jié)一下編譯前端的所閱歷的流程:經(jīng)過(guò)源碼輸入,對(duì)源碼停止詞法剖析將源碼停止內(nèi)容切割生成原子token。經(jīng)過(guò)語(yǔ)法剖析對(duì)原子token的組合停止語(yǔ)法模板匹配,生成籠統(tǒng)語(yǔ)法樹(shù)(AST)。經(jīng)過(guò)語(yǔ)義剖析,對(duì)籠統(tǒng)語(yǔ)法樹(shù)停止遍歷生成中間代碼IR與符號(hào)表信息內(nèi)容。
3.2、編譯器后端
編譯器后端主要做了兩件重要的事情: 1、優(yōu)化中間層代碼LLVMIR(閱歷屢次的Pass操作) 2、生成匯編代碼,最終鏈接生成機(jī)器碼
編譯器前端完成編譯后,生成了相關(guān)的編譯產(chǎn)物L(fēng)LVMIR,LLVMIR會(huì)經(jīng)過(guò)優(yōu)化器停止優(yōu)化,優(yōu)化的過(guò)程會(huì)閱歷一個(gè)又一個(gè)的Pass操作,什么是Pass呢?援用官方的解釋?zhuān)?br/>
The LLVM Pass Framework is an important part of the LLVM system, because LLVM passes are where most of the interesting parts of the compiler exist. Passes perform the transformations and optimizations that make up the compiler, they build the analysis results that are used by these transformations, and they are, above all, a structuring technique for compiler code.
我們能夠了解為一個(gè)個(gè)的中間過(guò)程的優(yōu)化,比方指令選擇、指令調(diào)度、存放器的分配等,輸入輸出也都是IR,如下圖:
在最終優(yōu)化完成之后,會(huì)生成一張DAG圖給到后端。我們曉得DAG是一張有向的非環(huán)圖,這個(gè)特性能夠用來(lái)標(biāo)識(shí)硬件的特定次第,便當(dāng)后端的內(nèi)容處置。我們也能夠依據(jù)本人的需求經(jīng)過(guò)繼承Pass來(lái)寫(xiě)一些自定義的Pass用于自定義的優(yōu)化,官方關(guān)于自定義的Pass也有相關(guān)的闡明,感興味的同窗能夠去看看(鏈接放在本文最后了)。在經(jīng)過(guò)優(yōu)化之后,后端根據(jù)不同架構(gòu)的編譯器生成對(duì)應(yīng)的匯編代碼,最終經(jīng)過(guò)鏈接完成機(jī)器碼的整體生成。
四、編譯器讓計(jì)算機(jī)更懂人類(lèi)
能夠發(fā)現(xiàn)編譯器是計(jì)算機(jī)高級(jí)言語(yǔ)的中梁砥柱,如今隨著高級(jí)言語(yǔ)的開(kāi)展越來(lái)越疾速,向著簡(jiǎn)單高效靈敏的方向不時(shí)行進(jìn),這里面與編譯器的開(kāi)展有著親密的聯(lián)絡(luò)。同時(shí)隨著編譯器的開(kāi)展晉級(jí),讓高級(jí)言語(yǔ)到低級(jí)言語(yǔ)的轉(zhuǎn)換變得更高效,同時(shí)也為諸多的跨平臺(tái)言語(yǔ)完成提供了諸多可能。經(jīng)過(guò)對(duì)計(jì)算機(jī)底層言語(yǔ)的層層籠統(tǒng),降生了我們所熟知的計(jì)算機(jī)高級(jí)言語(yǔ),讓我們可以用人類(lèi)的思想邏輯停止指令輸入,而籠統(tǒng)的層層翻譯處置則交給了編譯器,它的存在樹(shù)立了人類(lèi)與計(jì)算機(jī)溝通的重要橋梁。