大型專案無法將所有程式碼置於單一檔案。模組化拆分不僅便於團隊協作,更允許單獨重新編譯修改過的模組,大幅縮短建置時間。但隨之而來的核心問題是:一個檔案定義的變數/函數,如何在另一個檔案安全使用?同名實體會不會衝突?
gcc -E)gcc -S)gcc -c),此時尚缺啟動代碼與庫函數實體gcc *.o -o exe)雖然原始碼物理分散,但邏輯上必須保持「相容」:全域符號(函數、變數)不可重複定義、僅能有一個 main 入口。C 語言預設檔案作用域限制了跨檔案直接存取,打破這層限制的關鍵正是頭文件。
將單一檔案拆分為三模組:
main.c:主流程、使用者互動、調用其他模組gen_rnd.c:隨機數生成(電腦出拳)judge.c:勝負判定邏輯各模組自行 #include 所需標準庫頭文件(如 stdio.h、stdlib.h),main.c 另以函數原型宣告告知編譯器 gen_rnd()、judge() 的介面資訊。
# 產生目標檔 gcc -c main.c gen_rnd.c judge.c # 產生 main.o gen_rnd.o judge.o # 鏈接生成可執行檔 gcc main.o gen_rnd.o judge.o -o game
鏈接器根據 main.o 中的未解析符號引用,從 gen_rnd.o、judge.o 及標準庫中尋找定義,完成符號解析與地址綁定。
頭文件本質上是跨檔案的介面契約:宣告而非定義,提供編譯期的型別檢查與符號解析依據;真正的定義留在 .c 檔,由鏈接期解析地址。這正是「宣告與定義分離」的工程化實踐。