C語言從編譯到運行
一、前言
最近在看CSAPP(深入理解計算機系統)然后以前也學過C語言,但是從來沒有深究寫好的C代碼是怎么編譯再到執行的。
所以現在自己學習,然后記錄下來。
以最常用的hello world!程序為例 程序名: main.c
#include <stdio.h> int main() { printf("Hello world!\n"); return 0; }
二、C程序編譯過程
hello程序的生命周期是從一個高級C語言程序開始的,為了能夠運行hello.c程序,每一條C語句都被其他程序轉化為一系列的低級機器語言指令。然后這些指令按照一種稱為可執行目標程序的格式打包,以二進制磁盤文件的形式存放起來。目標程序也稱為可執行目標文件。
編譯一個 C程序可以分為四階段:預處理階段--->生成匯編代碼階段--->匯編階段--->鏈接階段
各個階段的代碼可以通過gcc指令來生成
如果沒有gcc可以用下面指令安裝
sudo apt-get build-dep gcc
安裝完之后可以根據以下指令查看是否安裝成功
gcc --version
安裝好后用下面指令生成中間文件
gcc main.c 直接生成可執行文件 a.out gcc -E main.c -o hello.i 生成預處理后的代碼 gcc CS main.c -o hello.s 生成匯編代碼 gcc Cc main.c -o hello.o 生成目標代碼
三、階段過程
1、預處理階段
gcc -E main.c -o hello.i 生成預處理后的代碼
預處理器(cpp)根據以字符 # 開頭的命令,修改原始的C程序。比如mian.c中第一行的 #include<stdio.h> 命令就告訴預處理器讀取系統頭文件stdio.h的內容,并且把它直接插入程序文本中。同時刪除注釋行,添加行號和文件名標識。這樣就得到了另一個C程序,通常是以 .i 作為文件擴展名。 所以經過預編譯的 .i 文件是不包含宏定義的。
處理完后我們來看看 hello.i 文件。發現原來的7行代碼變成了700多行,我們的代碼在最后面。而前面多出來的代碼就是 .c 中#include<stdio.h>展開的代碼。
2、編譯階段
gcc CS main.c -o hello.s 生成匯編代碼
編譯是將源文件(hello.i)翻譯成匯編文件(hello.s)的過程。中間包含詞法、語法分析等步驟,具體過程可以參考《編譯原理》。
打開匯編代碼我們會發現里面有很多以 . 開頭的行,所有這些以 . 開頭的行都是指導匯編器和鏈接器工作的偽指令。 我們通常可以忽略這些行。
去掉這些行后剩下的部分。
3、匯編階段
gcc Cc main.c -o hello.o 生成目標代碼
匯編階段是把編譯階段生成的 .s 文件轉成 .o 的二進制目標代碼。匯編器(as)將 hello.s 翻譯成機器語言指令,把這些指令打包成一種叫做可重定位目標程序的格式
,并將結果保存在目標文件hello.o中。hello.o文件是一個二進制文件,它的字節編碼是機器語言指令而不是字符。如果我們在文本編譯器中打開 hello.o 文件,看到的將是一堆亂碼。
你非要看就是這樣
4、鏈接階段
這個階段就是把匯編后的機器指令集變成可以直接運行的文件,而對目標文件進行鏈接主要是因為在目標文件中可能用到了在其他文件當中定義的字段(或者函數),通過鏈接來把多個不同目標文件關聯到一起。
hello 程序調用了printf 函數,它是每個 C 編譯器都會提供的標準C庫中的一個函數,printf 函數存在于一個名為 printf.o 的單獨預編譯好了的標準文件中,而這個文件必須以某種方式合并到我們的 hello.o 程序中,鏈接器(ld)就負責處理這種合并,結果就得到 hello 文件,它是一個可執行目標文件(簡稱:可執行文件),可以被加載到內存中,有系統執行。
以上就是C語言從編譯到運行過程詳解的詳細內容,更多關于C語言從編譯到運行的資料請關注服務器之家其它相關文章!
原文鏈接:https://www.cnblogs.com/stevenchow/p/14930206.html