連結錯誤(undefined reference、multiple definition)
許多初學者會撞上一個困惑的時刻:編譯器說一切沒問題,建構卻仍失敗,訊息很奇怪、沒有提到你程式碼裡的任何行號。那幾乎總是連結錯誤。它來自最後一個階段,在每個檔案各自編譯成功之後,當連結器試著把檔案接在一起、卻發現名稱對不上時。因為問題在於檔案如何連接,而非任何單一行,這些訊息看起來和編譯器錯誤不同。
你遇到最多的兩個,彼此互為鏡像。「undefined reference to add」表示某個檔案用了 add 這個名稱,但沒有任何目的檔或函式庫實際定義它:連結器到處找,找到一個被需要卻沒有提供者的符號。典型原因有:忘了編譯或連結定義它的那個 .c 檔、名稱拼錯、在 C++ 中因名稱修飾而簽章不符,或忘了連結某個函式庫。「multiple definition of count」表示相反的情形:count 這個名稱同時在兩處被定義,所以連結器無法挑一個。經典原因是把真正的定義(不只是宣告)放進好幾個檔案都引入的標頭檔,於是每一個都烤進了自己的副本。
解法隨原因而來。對「undefined reference」,檢查定義用的原始檔確實是建構的一部分、名稱與簽章相符,並把任何缺少的函式庫加進連結指令。對「multiple definition」,把定義從標頭檔移到單一個 .c 檔,標頭檔裡只留宣告(常用 extern),並以引入防護保護。更深的教訓是:「它能編譯」不等於「它能建構」:通過編譯器只證明了每個檔案內部一致,而連結器檢查的是檔案彼此之間是否一致。
$ gcc main.c -o app # 忘了納入 utils.c! /usr/bin/ld: main.o: in function `main': main.c:(.text+0x12): undefined reference to `add' # 修正: $ gcc main.c utils.c -o app
編譯乾淨卻仍無法連結,因為定義 add 的檔案被排除在建構之外。
連結錯誤通常不帶原始碼行號,因為問題在檔案之間、而非單一檔案之內;通過編譯器完全無法證明這些零件能否連結在一起。