C源代碼是如何跑起來的?
- 2019 年 12 月 25 日
- 筆記
本文 1273 個字,預計閱讀 5 分鐘
身為程序猿,C 語言大家一定都不陌生了,還記得當年在黑窗口中第一次顯示出 hello, wordl! 時激動的心情嗎?平時我們在寫 C 程序時都用 IDE(集成開發環境),寫好源代碼之後點一下按鈕,一鍵運行。但是不同的 IDE 會出現不同的按鈕,甚至還有多個按鈕,什麼先點編譯,後點運行(當時老師就是這麼說的,咱也不知道為什麼,照着做就是了)。

隨着越來越深入了解計算機,我逐漸地明白了其中的執行過程,看似寫好的 C 代碼點一下就可以運行,其實這都是 IDE 幫我們集成好的,它私下裡偷偷地幫我們做了許多工作呢。讓我們一起來看看 C 源代碼是如何跑起來的。
C 程序從源代碼到運行階段一共需要進行如下幾個階段。

那究竟是怎樣進行的呢?我們一起來看一看。
我們在 Ubuntu 上用 gcc 編譯器對 C 代碼進行處理。首先用 vim 寫一個 C 程序,就寫最簡單的 hello, world 吧。

1.
進行預處理,調用預處理器,使用命令 gcc -E hello.c -o hello.i
現在生成了一個名為 hello.i 的文件,打開來看一下有什麼變化。

可以看到,在源代碼的基礎上,#include<stdio.h> 所在的語句沒有了,與之替換的是一堆聲明,增加了幾百行,也就是說,在預處理階段,預處理器會將我們 C 源代碼中的所有宏定義(帶 # 符號的語句)進行替換。
2.
進行編譯,調用編譯器,使用命令 gcc -S hello.i -o hello.s
現在生成了一個名為 hello.s 的文件,打開看一看。

如果你學過彙編語言的話,就會很熟悉,這裡全部都是彙編語言。在編譯階段,編譯器會將剛才經過預處理器處理過的文件進行編譯,將 C 代碼(高級語言)翻譯成彙編語言代碼(低級語言)。
3.
進行彙編,調用彙編器,使用命令 gcc -c hello.s -o hello.o
生成了 hello.o 文件(該文件是可重定位目標文件),這裡如果我們再用文本編輯軟件打開該文件,會發現一堆亂碼,因為現在該文件已經是二進制文件,文本編輯軟件只能查看文本文件,如果按照文本解析的方式解析二進制文件就會產生亂碼。在預處理、編譯階段,我們都可以查看其生成的文件,只有在彙編這一步打開會產生亂碼,我們可以知道,彙編器將彙編語言代碼翻譯成二進制文件。因為計算機只能執行二進制文件。
到目前為止,已經生成了二進制文件 hello.o, 如果你去運行,一定會報錯,這是因為還差最後一步——鏈接。
4.
鏈接的作用是幹什麼呢?還記得我們之前寫代碼時調用的 printf() 函數嗎?這個函數是在標準庫中定義的,我們寫 hello.c 源代碼時沒有對它進行定義,只對它進行調用,C 程序不認識這個函數,想要讓 C 程序認識這個函數就必須找到它定義的位置,鏈接就是負責把我們在源代碼中調用的函數從它定義的文件中加載過來。
5.
鏈接完成之後,我們就可以調用加載器對該程序進行加載運行,最激動人心的時刻就要到來了,經過一系列複雜的步驟,屏幕上終於顯示出了 Hello, world!

嗨,你還在看嗎?