
- C程式設計教程
- C語言 - 首頁
- C語言基礎
- C語言 - 概述
- C語言 - 特性
- C語言 - 歷史
- C語言 - 環境搭建
- C語言 - 程式結構
- C語言 - Hello World
- C語言 - 編譯過程
- C語言 - 註釋
- C語言 - 詞法單元
- C語言 - 關鍵字
- C語言 - 識別符號
- C語言 - 使用者輸入
- C語言 - 基本語法
- C語言 - 資料型別
- C語言 - 變數
- C語言 - 整數提升
- C語言 - 型別轉換
- C語言 - 型別強制轉換
- C語言 - 布林值
- C語言中的常量和字面量
- C語言 - 常量
- C語言 - 字面量
- C語言 - 轉義序列
- C語言 - 格式說明符
- C語言中的運算子
- C語言 - 運算子
- C語言 - 算術運算子
- C語言 - 關係運算符
- C語言 - 邏輯運算子
- C語言 - 位運算子
- C語言 - 賦值運算子
- C語言 - 一元運算子
- C語言 - 自增和自減運算子
- C語言 - 三元運算子
- C語言 - sizeof 運算子
- C語言 - 運算子優先順序
- C語言 - 其他運算子
- C語言中的決策機制
- C語言 - 決策機制
- C語言 - if 語句
- C語言 - if...else 語句
- C語言 - 巢狀 if 語句
- C語言 - switch 語句
- C語言 - 巢狀 switch 語句
- C語言中的迴圈
- C語言 - 迴圈
- C語言 - while 迴圈
- C語言 - for 迴圈
- C語言 - do...while 迴圈
- C語言 - 巢狀迴圈
- C語言 - 無限迴圈
- C語言 - break 語句
- C語言 - continue 語句
- C語言 - goto 語句
- C語言中的函式
- C語言 - 函式
- C語言 - 主函式
- C語言 - 按值呼叫函式
- C語言 - 按引用呼叫函式
- C語言 - 巢狀函式
- C語言 - 可變引數函式
- C語言 - 使用者自定義函式
- C語言 - 回撥函式
- C語言 - return 語句
- C語言 - 遞迴
- C語言中的作用域規則
- C語言 - 作用域規則
- C語言 - 靜態變數
- C語言 - 全域性變數
- C語言中的陣列
- C語言 - 陣列
- C語言 - 陣列的特性
- C語言 - 多維陣列
- C語言 - 將陣列傳遞給函式
- C語言 - 從函式返回陣列
- C語言 - 變長陣列
- C語言中的指標
- C語言 - 指標
- C語言 - 指標和陣列
- C語言 - 指標的應用
- C語言 - 指標運算
- C語言 - 指標陣列
- C語言 - 指向指標的指標
- C語言 - 將指標傳遞給函式
- C語言 - 從函式返回指標
- C語言 - 函式指標
- C語言 - 指向陣列的指標
- C語言 - 指向結構體的指標
- C語言 - 指標鏈
- C語言 - 指標與陣列的區別
- C語言 - 字元指標和函式
- C語言 - 空指標
- C語言 - void 指標
- C語言 - 懸空指標
- C語言 - 解引用指標
- C語言 - 近指標、遠指標和巨大指標
- C語言 - 指標陣列的初始化
- C語言 - 指標與多維陣列的區別
- C語言中的字串
- C語言 - 字串
- C語言 - 字串陣列
- C語言 - 特殊字元
- C語言中的結構體和聯合體
- C語言 - 結構體
- C語言 - 結構體和函式
- C語言 - 結構體陣列
- C語言 - 自引用結構體
- C語言 - 查詢表
- C語言 - 點 (.) 運算子
- C語言 - 列舉 (enum)
- C語言 - 結構體填充和打包
- C語言 - 巢狀結構體
- C語言 - 匿名結構體和聯合體
- C語言 - 聯合體
- C語言 - 位域
- C語言 - typedef
- C語言中的檔案處理
- C語言 - 輸入與輸出
- C語言 - 檔案I/O (檔案處理)
- C語言預處理器
- C語言 - 預處理器
- C語言 - 編譯指示
- C語言 - 預處理器運算子
- C語言 - 宏
- C語言 - 標頭檔案
- C語言中的記憶體管理
- C語言 - 記憶體管理
- C語言 - 記憶體地址
- C語言 - 儲存類
- 其他主題
- C語言 - 錯誤處理
- C語言 - 可變引數
- C語言 - 命令執行
- C語言 - 數學函式
- C語言 - static 關鍵字
- C語言 - 隨機數生成
- C語言 - 命令列引數
- C語言程式設計資源
- C語言 - 問答
- C語言 - 快速指南
- C語言 - 速查表
- C語言 - 有用資源
- C語言 - 討論
C語言編譯過程
C 是一種編譯型語言。與解釋型語言相比,編譯型語言執行速度更快。可以使用不同的編譯器產品來編譯 C 程式,例如 GCC、Clang、MSVC 等。本章將解釋使用 GCC 編譯器編譯 C 程式時後臺發生的情況。
編譯C程式
一系列由 1 和 0 組成的二進位制指令被稱為機器碼。C、C++、Java 等高階程式語言包含更接近人類語言(如英語)的關鍵字。因此,用 C(或任何其他高階語言)編寫的程式需要轉換為其等效的機器碼。這個過程稱為編譯。
請注意,機器碼是特定於硬體架構和作業系統的。換句話說,在 Windows 作業系統的計算機上編譯的特定 C 程式的機器碼與使用 Linux 作業系統的另一臺計算機不相容。因此,我們必須使用適合目標作業系統的編譯器。

C語言編譯過程步驟
在本教程中,我們將使用 gcc(代表 GNU 編譯器集合)。GNU 專案是由 Richard Stallman 發起的自由軟體專案,允許開發人員免費訪問強大的工具。
gcc 編譯器支援多種程式語言,包括 C 語言。為了使用它,我們應該安裝與其目標計算機相容的版本。
編譯過程包含四個不同的步驟:
- 預處理
- 編譯
- 彙編
- 連結
下圖說明了編譯過程。

示例
為了理解這個過程,讓我們考慮以下 C 語言原始碼 (main.c):
#include <stdio.h> int main(){ /* my first program in C */ printf("Hello World! \n"); return 0; }
輸出
執行程式碼並檢查其輸出:
Hello World!
“.c” 是一個副檔名,通常表示該檔案是用 C 編寫的。第一行是預處理指令#include,它告訴編譯器包含stdio.h標頭檔案。/* 和 */ 之間的文字是註釋,這些註釋對於文件目的很有用。
程式的入口點是main() 函式。這意味著程式將首先執行此函式塊內的語句。在此給定的程式程式碼中,只有兩條語句:一條語句將在終端列印句子“Hello World”,另一條語句告訴程式如果它正確退出或結束則“返回 0”。因此,一旦我們編譯它,如果我們執行此程式,我們將只看到顯示的短語“Hello World”。
C編譯過程內部發生了什麼?
為了使我們的“main.c”程式碼可執行,我們需要輸入命令“gcc main.c”,編譯過程將經歷其包含的四個步驟。
步驟 1:預處理
預處理器執行以下操作:
- 它刪除原始檔中的所有註釋。
- 它包含標頭檔案(.h)的程式碼,標頭檔案包含 C 函式宣告和宏定義。
- 它用其值替換所有宏(已命名的程式碼片段)。
此步驟的輸出將儲存在副檔名為“.i”的檔案中,因此這裡將儲存在“main.i”中。
為了在此步驟之後停止編譯,我們可以對原始檔使用 gcc 命令的“-E”選項,然後按 Enter。
gcc -E main.c
步驟 2:編譯
編譯器從預處理檔案生成 IR 程式碼(中間表示),因此這將生成一個“.s”檔案。也就是說,其他編譯器可能在此編譯步驟中生成彙編程式碼。
我們可以使用 gcc 命令的“-S”選項在該步驟後停止,然後按 Enter。
gcc -S main.c
main.s 檔案應如下所示:
.file "helloworld.c" .text .def __main; .scl 2; .type 32; .endef .section .rdata,"dr" .LC0: .ascii "Hello, World! \0" .text .globl main .def main; .scl 2; .type 32; .endef .seh_proc main main: pushq %rbp .seh_pushreg %rbp movq %rsp, %rbp .seh_setframe %rbp, 0 subq $32, %rsp .seh_stackalloc 32 .seh_endprologue call __main leaq .LC0(%rip), %rcx call puts movl $0, %eax addq $32, %rsp popq %rbp ret .seh_endproc .ident "GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0" .def puts; .scl 2; .type 32; .endef
步驟 3:彙編
彙編器獲取 IR 程式碼並將其轉換為機器語言程式碼(即二進位制程式碼)。這將生成一個以“.o”結尾的檔案。
我們可以透過使用 gcc 命令的“-c”選項並在之後按 Enter 來在此步驟之後停止編譯過程。
請注意,“main.o”檔案不是文字檔案,因此當您使用文字編輯器開啟此檔案時,其內容將不可讀。
步驟 4:連結
連結器建立最終的可執行二進位制檔案。它將所有原始檔的目的碼連結在一起。連結器知道在哪裡查詢靜態庫或動態庫中的函式定義。
靜態庫是連結器將所有使用的庫函式的副本複製到可執行檔案的結果。動態庫中的程式碼不會被完全複製,只有庫的名稱會被放在二進位制檔案中。
預設情況下,在此第四個也是最後一步之後,也就是在您鍵入完整的“gcc main.c”命令沒有任何選項時,編譯器將建立一個名為main.out(或在 Windows 系統中為main.exe)的可執行程式,我們可以從命令列執行它。
我們還可以透過向 gcc 命令新增“-o”選項來建立我們想要名稱的可執行程式,該選項放置在我們正在編譯的檔案或檔案的名稱之後。
gcc main.c -o hello.out
因此,現在我們可以鍵入“./hello.out”(如果您沒有使用“-o”選項)或“./hello”來執行編譯後的程式碼。輸出將是“Hello World”,之後將再次出現 shell 提示符。