編譯器

在 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 檔案轉換為可執行檔案時,編譯器會執行以下四個步驟:

  1. 預處理 - 在 .c 檔案中以文字方式展開 #include 指令和 #define 巨集
  2. 編譯 - 將程式轉換為程式集(你可以通過新增 -S 選項在此步驟停止編譯器)
  3. assembly - 將程式集轉換為機器程式碼
  4. 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