hi,各位,讓我們開啟今日份博客~
小編個人主頁點這里~
目錄
- 一、翻譯環境和運行環境
- 1、翻譯環境
- 1.1預處理(預編譯)
- 1.2編譯
- 1.2.1詞法分析
- 1.2.2語法分析
- 1.2.3語義分析
- 1.3匯編
- 1.4鏈接
- 2.運行環境
一、翻譯環境和運行環境
在ANSI C(ANSI C 是美國國家標準協會創立的一套C標準,于1989年完成,這個版本的語言常被叫做C89.) 的任何一種實現中,存在兩個不同的環境。
第一種是翻譯環境,在這個環境中,源代碼被轉換成可執行的機器指令(二進制指令)。
第二種是運行環境,它用于實際執行代碼。
1、翻譯環境
翻譯由編譯和鏈接兩大部分組成,其中編譯又分為預處理、編譯、匯編三個過程。
在編譯器中一個C語言的項目可能有多個.c文件一起構建,那多個.c文件如何生成可執行程序呢?
- 首先多個.c文件單獨經過編譯器,編譯處理成對應的目標文件(在Windows環境下的目標文件后綴是.obj,Linux環境下目標文件的后綴是.o)
- 然后多個目標文件和編譯庫一起經過鏈接器處理生成最終的可執行程序(鏈接庫是指運行時庫【它是支持程序運行的基本函數集合】或者第三方庫)。
如果我們再把編譯器分成預處理、編譯、匯編這三個過程,那就變成了以下過程:
1.1預處理(預編譯)
在預處理階段,源文件和頭文件會被處理成.i為后綴的文件.
在gcc下觀察對test.c文件預處理后的test.i文件,命令如下:
gcc test.c -E -o test.i
- -E選項:提示編譯器執行完當前命令后就停下來,后面的編譯、匯編和鏈接暫不執行
- -S選項:提示編譯器執行完編譯停下來,匯編、鏈接暫不執行
- -c選項:提示編譯器執行完匯編就停下來
預處理過程進行的操作:
1、對#include 頭文件進行包含
2、刪除代碼中的注釋(使用空格替換)
3、#define 定義的符號進行替換,使用完后,符號刪除
1.2編譯
編譯是將C語言程序轉換成了匯編代碼
在gcc下觀察對test.i文件編譯后的test.s文件,命令如下:
gcc test.i -S -o test.s
1.2.1詞法分析
詞法分析是使用一種叫做lex的程序實現詞法掃描,它會按照用戶之前描述好的詞法規則將輸入的字符串分割成一個個記號。產生的記號一般分為:關鍵字、標識符、字面量(包含數字、字符串等)和特殊符號(運算符、等號等),然后他們放到對應的表中。
我們以以下表達式為例進行詞法分析:
array[index] = (index+4)*(2+6);
1.2.2語法分析
語法分析器根據用戶給定的語法規則,將詞法分析產生的記號序列進行解析,然后將它們構成一棵語法樹。這些語法樹是以表達式為節點的樹,對于不同的語言,只是其語法規則不一樣。
如下:
1.2.3語義分析
語義分析是由語義分析器來完成的,即對表達式的語法層?分析。編譯器所能做的分析是語義的靜態分析。靜態語義分析通常包括聲明和類型的匹配,類型的轉換等。這個階段還會報告錯誤的語法信息。
如下:
1.3匯編
匯編過程是通過匯編器來完成的,匯編器將匯編代碼轉變成機器可執?的指令(2進制的指令),每?個匯編語句?乎都對應?條機器指令。它是根據匯編指令和機器指令的對照表一一 的進行翻譯的,不做指令優化。
gcc下匯編命令如下:
gcc -c test.s -o test.o
1.4鏈接
鏈接是?個復雜的過程,鏈接的時候需要把?堆?件鏈接在?起才?成可執?程序。鏈接過程主要包括:地址和空間分配,符號決議和重定位等。
符號解析: 目標文件中可能包含一些未定義的符號引用,如函數調用、全局變量引用等。鏈接器會在所有的目標文件和庫文件中查找這些符號的定義,將符號引用與對應的符號定義進行匹配,確保每個符號都有正確的定義。
重定位:編譯生成的目標文件中的地址通常是相對地址或未確定的地址。鏈接器會根據最終可執行文件或庫文件的布局,對目標文件中的代碼和數據進行重定位,將相對地址轉換為絕對地址,使程序在運行時能夠正確地訪問代碼和數據。
合并段:目標文件通常包含多個段,如代碼段、數據段、只讀數據段等。鏈接器會將各個目標文件中的相同類型的段進行合并,形成最終可執行文件或庫文件中的相應段,并為每個段分配合適的內存地址。
在生成輸出文件時,還會添加一些必要的頭部信息,如程序入口點、段的屬性等,以便操作系統能夠正確的加載和執行程序。
2.運行環境
程序必須載入內存中,在有操作系統的環境中,一般由操作系統來完成,在獨立的環境中,程序的載入必須由手工安排,也可能是通過可執行代碼置入只讀內存來完成。程序載入內存之后,執行才能開始,開始后首先調用main函數,開始執行程序代碼。這個時候程序將使用一個運行時堆棧(stack),儲存函數的局部變量和返回的地址,程序同時也可以使用靜態(static)內存,儲存于靜態內存中的變量在程序的整個執行過程一直保留他們的值,正常終止main函數時,程序終止,也有可能是意外終止。
如上圖,我們雙擊以.exe結尾的可執行文件就會進入運行環境,此時程序已經被加載到內存中。
總結:
以上就是本期博客分享的全部內容啦!技術的探索永無止境。
道阻且長,行則將至!后續我會給大家帶來更多博客內容,歡迎關注我的CSDN賬號,我們一同成長!
(~ ̄▽ ̄)~