編譯原理概述

2021-05-24 08:44:26 字數 3012 閱讀 8332

一、編譯過程分析

編譯軟體讀取源程式(字元流),對之進行詞法和語法的分析,將高階語言指令轉換為功能等效的彙編**,再由匯程式設計序轉換為機器語言,並按照作業系統對可執行檔案格式的要求鏈結生成可執行程式.

二、編譯流程表

c源程式(.c檔案)             (編輯器)-->

預處理過程(.c檔案)                  -->

編譯、優化過程(.s或.asm檔案)  (編譯器)-->

彙編過程(.o或.obj檔案)       (彙編器)-->

鏈結過程(.exe檔案、.elf檔案、.bin檔案等) (鏈結器ld)

三、

預處理過程

該階段主要工作是讀取c源程式,對其中的偽指令(以#開頭的指令)和特殊符號進行處理.

偽指令主要包括以下4個方面:

(1)巨集定義指令,如#define、#undef等.

對於#define定義的偽指令,預編譯所要做的就是將程式中的所有巨集定義進行替換.

對於#undef定義的偽指令,則將取消對某個巨集的定義,使以後該串的出現不再被替換.

(2)條件編譯,如#ifdef、#ifndef、#else、#endif等.

對於這些偽指令的引入,使得程式設計師可以通過定義不同的巨集來決定編譯程式對哪些**進行處理.預編譯程式將根據有關的檔案,將那些不必要的**過濾掉.

(3)標頭檔案包含指令,如#include等.

採用標頭檔案的目的主要是為了使某些定義可以供多個不同的c原始碼程式使用.因為在需要用到這些定義的c源程式中,只需加上一條#include語句即可,而不必再在此檔案中將這些定義重複一遍.包含到c源程式中的標頭檔案可以是系統提供的,這些標頭檔案一般被放在/usr/include目錄下.在程式中#include它們要使用尖括號(<>);另外開發人員也可以定義自己的標頭檔案,這些檔案一般放在同一目錄下,此時在#include中要用雙引號("").

(4)特殊符號,預編譯程式可以識別一些特殊符號.

通過上面的描述可知,預編譯程式所完成的基本上是對源程式的"替代"工作.經過這種替代,生成乙個沒有巨集定義、沒有條件編譯指令、沒有特殊符號的輸出檔案.這個檔案的含義同沒有經過預處理的源程式是相同的,但內容有很大的不同.

在linux系統中,編譯的各個過程是可控的.使用者可通過命令gcc -e hello.c -o hello.i,比較預處理前後檔案大小的變化.可以發現,預處理後生成的hello.i檔案遠大於hello.c,這是因為預處理後將庫函式都拷貝到原始檔中了.

預編譯結束後,檔案仍然是.c檔案.在linux中,預編譯後生成了.i檔案.

四、

編譯、優化過程

編譯的主要工作是通過詞法分析和語法分析,在確認所有的指令都符合語法規則後,將其翻譯成等待的中間**表示或彙編**.

優化是編譯系統中一項比較艱深的計數.它涉及的問題不僅同編譯技術本身有關,而且同機器的硬體環境也有很大的關係.優化主要有兩個方面:

一是考慮如何充分利用機器的各個硬體暫存器存放的有關變數的值,以減少對記憶體的訪問次數.

二是調整使目標**比較短,且執行效率比較高.

經過優化得到的彙編**必須經過匯程式設計序的彙編轉換成相應的機器指令,才可能被機器執行.

編譯、優化的c源程式變成了.s或.asm的匯程式設計序.

五、

彙編過程

彙編過程是指將組合語言**翻譯成目標機器指令.目標檔案就是與源程式等效的目標機器語言**.目標檔案由段組成.通常乙個目標檔案中至少有兩個段:

**段:該段中所包含的主要是程式的指令.該段一般是可讀和可執行的,但不可寫.

資料段:主要存放程式中要用到的各種全域性變數或靜態的資料.一般資料段都可讀、可寫、可執行.

實際上,彙編就是查表,根據指令通過查表生成相應的機器**.

彙編後的c源程式變成了.o或.obj的目標程式.

六、

鏈結過程

由彙編過程生成的目標檔案並不能立即被執行.其中還存在著一些問題.

比如,某個原始檔中的函式可能引用了另乙個原始檔中定義的某個符號(如變數或函式呼叫);程式中可能呼叫了某個庫檔案中的函式.所有這些問題都需要經過鏈結過程方能得到處理.

鏈結過程的主要工作是將有關的目標檔案彼此相連線,也即將在乙個檔案中引用的符號同該符號所在另外

乙個檔案中的定義連線起來,使得所有這些目標檔案能成為乙個能被作業系統裝入執行的統一整體.

舉例:一工程中包含三個檔案,分別是file1.c、file2.c、file3.c,通過編譯、彙編分別生成了file1.o、file2.o、file3.o,最後鏈結器將三個.o檔案根據平台的要求鏈結成乙個可執行檔案.在x86系統中,生成了.exe檔案.在linux系統中,生成了.elf檔案;在嵌入式系統中,生成了.bin檔案.

根據開發人員指定的同庫函式的鏈結方式不同,鏈結處理可分為兩種:

(1)靜態鏈結

在這種鏈結方式下,函式的**將從其所在地靜態鏈結庫中被拷貝到最終的可執行程式中.這種,該程式在被執行時,這些**將被裝入到該程序的虛擬位址空間中.靜態鏈結庫實際上是乙個目標檔案的集合,其中的每個檔案含有庫中的乙個或一組相關函式的**.

(2)動態鏈結

在這種鏈結方式下,函式的**被放到稱作是動態鏈結庫或共享物件的某個目標檔案中.鏈結程式此時所

作的只是在最終的可執行程式中記錄下共享物件的名字以及其它少量的登記資訊.在此可執行檔案被執行時,動態鏈結庫的全部內容將被對映到執行時相應程序的虛擬位址空間.動態鏈結程式將根據可執行程式中記錄的資訊找到相應的函式**.

attention!!!

(1)一般情況下,只需要知道分成編譯和鏈結兩個階段即可.

編譯階段是將源程式(.c)轉換為目標**(.obj).

鏈結階段是將源程式轉換成的目標**(.obj)與你程式中呼叫的庫函式對應的**鏈結起來形成的可執行檔案(.exe等).

(2)通過上面的描述可知:

無論是什麼平台,如x86平台、linux平台還是arm平台,預編譯後的.c檔案都相同,這與平台無關.但編譯後生成的.s或.i檔案,根據平台的不同,生成的結果也不同.

編譯原理概述

計算機不能直接理解 高階語言 只能直接理解 機器語言 所以必須要把高階語言 翻譯 成機器語言,計算機才能執行高階語言編寫的程式。我們可以粗略地把程式語言分為兩類 編譯型語言 和解釋型語言 常用的c c pascal和最近流行的go語言都是編譯型語言,而python ruby等則是解釋型語言,解釋型語...

編譯原理概述

編譯程式的工作過程 編譯程式的結構 編譯器的自舉和移植 高階語言轉換為可執行語言的過程 以gcc編譯器為例 原始檔為hello.c 步驟一 預處理。將原始檔hello.c預處理成hello.i。該步是將 include中包含的標頭檔案匯入到原始檔中。命令是gcc e hello.c 步驟二 編譯。將...

編譯原理 編譯過程概述

編譯程式即是將高階語言書寫的源程式翻譯成與之等價的目標程式 組合語言或機器語言 其工作可分為六個階段,見下圖 對於編譯的各個階段,邏輯上可以劃分為前端和後端兩部分。前端包括詞法分析到中間 生成中各個階段的工作,後端則是優化及目標 生成的階段。以中間 為分水嶺的原因是把編譯過程分解為與機器有關和無關兩...