編譯器的警告與錯誤(compiler warning vs error)
當你建構程式時,編譯器會以診斷訊息回應你,而它們有兩種強度。錯誤表示編譯器無法繼續:程式碼違反了語言的規則,所以不產生輸出,你必須先修正它,任何東西才能建構。警告表示程式碼合法到足以編譯,編譯器會產生輸出,但它注意到某個看起來可疑或很可能有誤的東西,選擇告訴你而非停下。錯誤是一道上鎖的門;警告是一個黃色的警示牌,你可以、但不智地,照樣開過去。
具體來說,漏掉的分號、未宣告的變數,或一個根本不可能成立的型別是錯誤,建構會中止。相對地,比較有號數與無號數、在變數初始化之前就使用它,或在你很可能想寫 == 時寫成 if (x = 5),這些是警告:每一個都能編譯成可運作的二進位檔,卻每一個都是真實錯誤的經典來源。編譯器預設對許多這類情況保持沉默,這就是為什麼有經驗的程式設計師會用像 -Wall 與 -Wextra 這樣的旗標把警告調高,並常加上 -Werror 把警告升級為錯誤,使建構在它們被處理之前拒絕完成。
該揚棄的危險誤解是:「它編譯時沒有錯誤」等於「我的程式是正確的」。並非如此。乾淨的編譯只證明程式碼遵守語言的文法與基本型別規則;它對邏輯是否正確隻字未提,當然也抓不到未定義行為,後者會悄悄地編譯,可能只在稍後才損毀或當掉。警告是編譯器盡力免費替你標出可能錯誤的舉動,所以把它們當成該忽略的雜訊,等於丟掉了你手上最便宜、最有效的找錯工具之一。
$ gcc -Wall main.c -o app main.c:4: warning: suggest parentheses around assignment used as truth value if (x = 5) { ... } // 能編譯也能執行,但你很可能想寫 x == 5 # 加上 -Werror 會把這個警告變成錯誤並停止建構
警告仍會建構出可執行的程式,但標出了一行很可能是錯誤的程式碼。
「沒有錯誤」只表示程式碼在文法上合法,不代表它正確;警告往往直指真正的錯誤,而未定義行為可能既無警告也無錯誤就編譯通過。