函式庫(library)
當你需要排序一份清單、與網路溝通,或做三角運算時,你幾乎從不從零自己寫那段程式碼——早有人寫好、測試好、打包好了。函式庫正是這個東西:一批已經編譯好、可重複使用的程式碼,再加上呼叫它的方式,許多不同的程式都能共用它。它相當於系統程式設計裡那本裝滿食譜、可以直接搬進你自己廚房的食譜書。
具體來說,函式庫把一組解決某個問題的函式(有時還有資料)綑在一起,例如 C 標準函式庫的 printf 與 malloc,或數學函式庫的 sin 與 sqrt。你不會把它的原始碼複製進你的專案;而是把你的程式建構成去呼叫那些函式,再把函式庫已編譯的機器碼,於建構時或執行時接到你的程式上。函式庫有兩張臉:一個宣告你能呼叫什麼的標頭檔(名稱、參數與回傳型別),以及真正實作那些呼叫的已編譯程式碼。
為什麼重要:函式庫是讓軟體由可重用零件組成、而非每次重新發明的方式,這省下龐大的工夫,並把除錯與最佳化集中到一處共享之地。函式庫有兩種行為相當不同的形式——靜態函式庫,於建構時複製進你的程式;以及動態(共享)函式庫,於程式執行時與它一同載入——理解這個區分,差不多就是「連結一個函式庫」的全部重點。
#include <math.h> // 函式庫的介面(標頭檔) ... double r = sqrt(2.0); // 呼叫進數學函式庫 建構: gcc main.c -lm // -lm 連結數學函式庫的程式碼
你引入標頭檔以呼叫那些函式,並連結函式庫,使它已編譯的程式碼被接上。
引入函式庫的標頭檔只給你它的宣告。若你忘了連結真正的函式庫(例如數學函式庫的 -lm),編譯會成功,但連結器會以「undefined reference」失敗——這個徵兆代表介面被找到了,實作卻沒有。