編譯器
在 C 前處理器包含所有標頭檔案並擴充套件所有巨集之後,編譯器可以編譯該程式。它通過將 C 原始碼轉換為目的碼檔案來實現,目的碼檔案是以 .o
結尾的檔案,其中包含原始碼的二進位制版本。但是,物件程式碼不能直接執行。為了生成可執行檔案,你還必須為檔案中的所有庫函式新增程式碼(這與包含宣告不同,這是 #include
的作用)。這是連結器的工作。
通常,如何呼叫 C 編譯器的確切順序在很大程度上取決於你使用的系統。這裡我們使用的是 GCC 編譯器,但需要注意的是存在更多的編譯器:
% gcc -Wall -c foo.c
%
是作業系統的命令提示符。這告訴編譯器在檔案 foo.c
上執行前處理器,然後將其編譯到目的碼檔案 foo.o
中。-c
選項意味著將原始碼檔案編譯為目標檔案,但不呼叫連結器。此選項 -c
可在 POSIX 系統上使用,例如 Linux 或 macOS; 其他系統可能使用不同的語法。
如果你的整個程式都在一個原始碼檔案中,你可以改為:
% gcc -Wall foo.c -o foo
這告訴編譯器在 foo.c
上執行前處理器,編譯它然後連結它以建立一個名為 foo
的可執行檔案。-o
選項表明該行的下一個單詞是二進位制可執行檔案(程式)的名稱。如果你沒有指定 -o
,(如果你只輸入 gcc foo.c
),由於歷史原因,可執行檔案將被命名為 a.out
。
通常,將 .c
檔案轉換為可執行檔案時,編譯器會執行以下四個步驟:
- 預處理 - 在
.c
檔案中以文字方式展開#include
指令和#define
巨集 - 編譯 - 將程式轉換為程式集(你可以通過新增
-S
選項在此步驟停止編譯器) - assembly - 將程式集轉換為機器程式碼
- linkage - 將目的碼連結到外部庫以建立可執行檔案
另請注意,我們使用的編譯器的名稱是 GCC,它代表“GNU C 編譯器”和“GNU 編譯器集合”,具體取決於上下文。存在其他 C 編譯器。對於類 Unix 作業系統,其中許多都有名稱 cc
,用於“C 編譯器”,它通常是一些其他編譯器的符號連結。在 Linux 系統上,cc
通常是 GCC 的別名。在 macOS 或 OS-X 上,它指向 clang。
POSIX 標準目前要求 c99
作為 C 編譯器的名稱 - 它預設支援 C99 標準。早期版本的 POSIX 強制要求 c89
作為編譯器。POSIX 還要求此編譯器理解我們上面使用的 -c
和 -o
選項。
注意: gcc
示例中的 -Wall
選項告訴編譯器列印有關可疑結構的警告,強烈建議這樣做。新增其他警告選項也是一個好主意,例如 -Wextra
。