gcc 編譯器提供了幾乎數不清的指令行選項清單。當然,沒有人會使用過或者精通它所有的指令行選項,但是有一些指令行選項是每一個 gcc 使用者都應該知道的 - 即使不是必須知道。它們中有一些很常用,其他一些不太常用,但不常用并不意味着它們的用處沒前者大。
不知道你是否能夠回想起,在這個系列教程的第一部分的開始,我簡要的提到了開發者們通常用來生成警告的 <code>-wall</code> 選項,并不包括一些特殊的警告。如果你不了解這些特殊警告,并且不知道如何生成它們,不用擔心,我将在這篇文章中詳細講解關于它們所有的細節。
除此以外,這篇文章也将涉及與浮點值相關的 gcc 警告選項,以及在 gcc 指令行選項清單變得很大的時候如何更好的管理它們。
在繼續之前,請記住,這個教程中的所有例子、指令和指令都已在 ubuntu 16.04 lts 作業系統和 gcc 5.4.0 上測試過。
<a target="_blank"></a>
盡管 gcc 編譯器的 <code>-wall</code> 選項涵蓋了絕大多數警告标記,依然有一些警告不能生成。為了生成它們,請使用 <code>-wextra</code> 選項。
比如,下面的代碼:
<code>#include <stdio.h></code>
<code>#include <stdlib.h></code>
<code>int main()</code>
<code>{</code>
<code>int i=0;</code>
<code>/* ...</code>
<code>some code here</code>
<code>...</code>
<code>*/</code>
<code></code>
<code>if(i);</code>
<code>return 1;</code>
<code>return 0;</code>
<code>}</code>
我不小心在 <code>if</code> 條件後面多打了一個分号。現在,如果使用下面的 gcc 指令來進行編譯,不會生成任何警告。
<code>gcc -wall test.c -o test</code>
但是如果同時使用 <code>-wextra</code> 選項來進行編譯:
<code>gcc -wall -wextra test.c -o test</code>
會生成下面這樣一個警告:
<code>test.c: in function ‘main’:</code>
<code>test.c:10:8: warning: suggest braces around empty body in an ‘if’ statement [-wempty-body]</code>
從上面的警告清楚的看到, <code>-wextra</code> 選項從内部啟用了 <code>-wempty-body</code> 選項,進而可以檢測可疑代碼并生成警告。下面是這個選項啟用的全部警告标記。
<code>-wclobbered</code>
<code>-wempty-body</code>
<code>-wignored-qualifiers</code>
<code>-wmissing-field-initializers</code>
<code>-wmissing-parameter-type</code> (僅針對 c 語言)
<code>-wold-style-declaration</code> (僅針對 c 語言)
<code>-woverride-init</code>
<code>-wsign-compare</code>
<code>-wtype-limits</code>
<code>-wuninitialized</code>
<code>-wunused-parameter</code> (隻有和 <code>-wunused</code> 或 <code>-wall</code> 選項使用時才會啟用)
<code>-wunused-but-set-parameter (隻有和</code>-wunused<code>或</code>-wall` 選項使用時才會生成)
此外,遇到下面這些情況, <code>-wextra</code> 選項也會生成警告:
一個指針和整數 <code>0</code> 進行 <code><</code>, <code><=</code>, <code>></code>, 或 <code>>=</code> 比較
(僅 c++)一個枚舉類型和一個非枚舉類型同時出現在一個條件表達式中
(僅 c++)有歧義的虛拟基底
(僅 c++)寄存器類型的數組加下标
(僅 c++)對寄存器類型的變量進行取址
(僅 c++)基類沒有在派生類的複制建構函數中進行初始化
下面是一段使用 <code>==</code> 運算符進行浮點值比較的代碼:
<code>#include<stdio.h></code>
<code>void compare(float x, float y)</code>
<code>if(x == y)</code>
<code>printf("\n equal \n");</code>
<code>int main(void)</code>
<code>compare(1.234, 1.56789);</code>
使用下面的 gcc 指令(包含 <code>-wall</code> 和 <code>-wextra</code> 選項)來編譯這段代碼:
遺憾的是,上面的指令沒有生成任何與浮點值比較相關的警告。快速看一下 gcc 手冊,在這種情形下可以使用一個專用的 <code>-wfloat-equal</code> 選項。
下面是包含這個選項的指令:
<code>gcc -wall -wextra -wfloat-equal test.c -o test</code>
下面是這條指令産生的輸出:
<code>test.c: in function ‘compare’:</code>
<code>test.c:5:10: warning: comparing floating point with == or != is unsafe [-wfloat-equal]</code>
正如上面你所看到的輸出那樣, <code>-wfloat-equal</code> 選項會強制 gcc 編譯器生成一個與浮點值比較相關的警告。
這背後的想法是,有時,對程式員來說,把浮點值考慮成近似無限精确的實數是友善的。如果你這樣做,那麼你需要通過分析代碼,或者其他方式,算出這種計算方式引入的最大或可能的最大誤差,然後進行比較時(以及産生輸出時,不過這是一個不同的問題)允許這個誤差。特别要指出,不應該檢查是否相等,而應該檢查兩個值是否可能出現範圍重疊;這是用關系運算符來做的,是以等值比較可能是搞錯了。
如果在你使用的 gcc 指令中,指令行選項清單變得很大而且很難管理,那麼你可以把它放在一個文本檔案中,然後把檔案名作為 gcc 指令的一個參數。之後,你必須使用 <code>@file</code> 指令行選項。
比如,下面這行是你的 gcc 指令:
然後你可以把這三個和警告相關的選項放到一個檔案裡,檔案名叫做 <code>gcc-options</code>:
<code>$ cat gcc-options&nbsp;</code>
<code>-wall -wextra -wfloat-equal</code>
這樣,你的 gcc 指令會變得更加簡潔并且易于管理:
<code>gcc @gcc-options test.c -o test</code>
下面是 gcc 手冊關于 <code>@file</code> 的說明:
從檔案中讀取指令行選項。讀取到的選項随之被插入到原始 <code>@file</code> 選項所在的位置。如果檔案不存在或者無法讀取,那麼這個選項就會被當成文字處理,而不會被删除。 檔案中的選項以空格分隔。選項中包含空白字元的話,可以用一個由單引号或雙引号包圍完整選項。任何字元(包括反斜杠: '\')均可能通過一個 '\' 字首而包含在一個選項中。如果該檔案本身包含額外的 <code>@file</code> 選項,那麼它将會被遞歸處理。
在這個系列的教程中,我們一共講解了 5 個不常見但是很有用的 gcc 指令行選項: <code>-save-temps</code>、<code>-g</code>、 <code>-wextra</code>、<code>-wfloat-equal</code> 以及 <code>@file</code>。記得花時間練習使用每一個選項,同時不要忘了浏覽 gcc 手冊上面所提供的關于它們的全部細節。
原文釋出時間為:2017-12-13
本文來自雲栖社群合作夥伴“linux中國”