簡體   English   中英

C 有哪些有用的 GCC 標志?

[英]What are the useful GCC flags for C?

除了設置-Wall和設置-std=XXX ,還有哪些其他真正有用但鮮為人知的編譯器標志可用於 C?

我對任何額外的警告和/或在某些情況下將警告轉化為錯誤特別感興趣,以絕對減少任何意外的類型不匹配。

這是我的:

  • -Wextra-Wall :必不可少。
  • -Wfloat-equal :很有用,因為通常測試浮點數的相等性很糟糕。
  • -Wundef :如果在#if指令中評估未初始化的標識符,則發出警告。
  • -Wshadow :每當一個局部變量遮蔽另一個局部變量、參數或全局變量,或者每當一個內置函數被遮蔽時發出警告。
  • -Wpointer-arith :警告是否有任何取決於函數或void的大小。
  • -Wcast-align :每當指針被-Wcast-align以增加目標所需的對齊方式時發出警告。 例如,在只能在兩字節或四字節邊界訪問整數的機器上,如果將char *強制轉換為int * ,則會發出警告。
  • -Wstrict-prototypes :如果在未指定參數類型的情況下聲明或定義函數,則發出警告。
  • -Wstrict-overflow=5 :警告編譯器基於不發生有符號溢出的假設進行優化的情況。 (值 5 可能過於嚴格,請參閱手冊頁。)
  • -Wwrite-strings :給字符串常量類型const char[ length ]以便將一個的地址復制到一個非const char *指針會得到一個警告。
  • -Waggregate-return :如果定義或調用了任何返回結構或聯合的函數,則發出警告。
  • -Wcast-qual :每當指針被-Wcast-qual以從目標類型* 中刪除類型限定符時發出警告。
  • -Wswitch-default :當switch語句沒有default case *-Wswitch-default警告。
  • -Wswitch-enum :每當switch語句具有枚舉類型的索引並且缺少該枚舉* 的一個或多個命名代碼的case-Wswitch-enum警告。
  • -Wconversion :警告可能改變值* 的隱式轉換。
  • -Wunreachable-code :如果編譯器檢測到代碼永遠不會被執行,則發出警告*

那些標記為* 的有時會發出太多虛假警告,因此我會根據需要使用它們。

幾個-f代碼生成選項很有趣:

  • -fverbose-asm如果您使用-S進行編譯以檢查程序集輸出,則它很有用 - 它添加了一些信息性注釋。

  • -finstrument-functions添加代碼以在每個函數入口和出口點調用用戶提供的分析函數。

  • --coverage檢測程序中的分支和調用,並創建覆蓋注釋文件,以便在程序運行時生成覆蓋數據,該數據可由gcov程序格式化以幫助分析測試覆蓋。

  • -fsanitize={address,thread,undefined}啟用 AddressSanitizer、ThreadSanitizer 和 UndefinedBehaviorSanitizer 代碼清理器。 這些檢測程序在運行時檢查各種錯誤。

以前這個答案也提到了-ftrapv ,但是這個功能已經被-fsanitize=signed-integer-overflow取代,它是-fsanitize=undefined啟用的清理器之一。

始終使用-O或更高版本( -O1-O2-Os等)。 在默認的優化級別,gcc 會提高編譯速度,並且沒有做足夠的分析來警告諸如未初始化變量之類的事情。

考慮制定-Werror策略,因為不會停止編譯的警告往往會被忽略。

-Wall幾乎打開了很可能是錯誤的警告。

-Wextra包含的警告傾向於標記常見的合法代碼。 它們可能對代碼審查很有用(盡管 lint 風格的程序發現更多的陷阱更靈活),但我不會為正常開發打開它們。

如果項目的開發人員不熟悉浮點,則-Wfloat-equal是個好主意,如果他們不熟悉,則是個壞主意。

-Winit-self很有用; 我想知道為什么它不包含在-Wuninitialized

-Wpointer-arith如果您的代碼大多是可移植的,而不能與-pedantic一起使用,那么它會-pedantic

-save-temps

這留下了預處理器和程序集的結果。

預處理的源代碼對於調試宏很有用。

該程序集可用於確定哪些優化生效。 例如,您可能想要驗證 GCC 是否正在對某些遞歸函數進行尾調用優化,因為沒有它,您可能會溢出堆棧。

我很驚訝還沒有人這么說 - 就我而言,最有用的標志是-g它將調試信息放入可執行文件中,以便您可以調試它並逐步執行源代碼(除非您精通並閱讀程序集和類似stepi命令)的程序在執行時。

-fmudflap -- 為所有危險的指針操作添加運行時檢查以捕獲 UB。 這有效地再次免疫您的程序緩沖區溢出並有助於捕獲各種懸空指針。

這是一個演示:

$ cat mf.c 
int main()
{
 int a[10];
 a[10]=1; // <-- o noes, line 4
}

$ gcc -fmudflap mf.c -lmudflap
$ ./a.out 
*******
mudflap violation 1 (check/write): time=1280862302.170759 ptr=0x7fff96eb3d00 size=44
pc=0x7f3a575503c1 location=`mf.c:4:2 (main)'
      /usr/lib/libmudflap.so.0(__mf_check+0x41) [0x7f3a575503c1]
      ./a.out(main+0x90) [0x400a54]
      /lib/libc.so.6(__libc_start_main+0xfd) [0x7f3a571e2c4d]
Nearby object 1: checked region begins 0B into and ends 4B after
mudflap object 0xf9c560: name=`mf.c:3:6 (main) a'
bounds=[0x7fff96eb3d00,0x7fff96eb3d27] size=40 area=stack check=0r/3w liveness=3
alloc time=1280862302.170749 pc=0x7f3a57550cb1
number of nearby objects: 1

與 C/C++ 並不真正相關,但無論如何都很有用:

@file

將上述所有好的標志(你們都指定了)放在一個“文件”中,並使用上面的標志來一起使用該文件中的所有標志。

例如:

文件:compilerFlags

-牆

-std=c99

-Wextra

然后編譯:

gcc yourSourceFile @compilerFlags

-march=native為您正在編譯的平台(=芯片)生成優化的代碼

如果您需要知道編譯器預定義的預處理器標志:

echo | gcc -E -dM -

它對於檢測錯誤並沒有真正的幫助,但是很少提及的-masm=intel選項使得使用-S來檢查程序集輸出更好、更好。

AT&T 匯編語法太讓我頭疼了。

我的 makefile 通常包含

  CFLAGS= -Wall -Wextra -Weffc++ -Os -ggdb
  ...
  g++ $(CFLAGS) -o junk $<
  gcc $(CFLAGS) -o $@ $<
  rm -f junk

其中最重要的選項之前已經討論過,所以我將指出尚未指出的兩個功能:

盡管我正在處理一個需要純 C 的代碼庫,以便移植到一些仍然沒有像樣的 C++ 編譯器的平台,我還是用 C++ 編譯器(除了 C 編譯器)進行了“額外”編譯。 這有 3 個好處:

  1. C++ 編譯器有時會給我比 C 編譯器更好的警告信息。
  2. C++ 編譯器接受 -Weffc++ 選項,它偶爾會給我一些有用的提示,如果我只用純 C 編譯它,我會錯過這些提示。
  3. 我可以使代碼相對容易移植到 C++,避免一些邊界條件,即普通的 C 代碼是無效的 C++ 代碼(例如定義一個名為“bool”的變量)。

是的,我是一個樂觀得無可救葯的 Pollyanna,她一直認為現在每個月肯定有一個平台要么被宣布過時,要么獲得一個不錯的 C++ 編譯器,我們最終可以切換到 C++。 在我看來,這是不可避免的——唯一的問題是,這是在管理層最終給每個人發小馬之前還是之后發生的。 :-)

這是一個沒有被提及的偉大標志:

-Werror-implicit-function-declaration

只要在聲明之前使用函數,就會報錯。

-Wstrict-prototypes -Wmissing-prototypes
man gcc

該手冊充滿了有趣的標志和良好的描述。 但是,-Wall 可能會使 gcc 盡可能冗長。 如果你想要更多有趣的數據,你應該看看 valgrind 或其他一些檢查錯誤的工具。

-Werror ,它將所有警告視為錯誤並停止編譯。 gcc手冊頁解釋了編譯器的每個命令行開關。

嗯, -Wextra應該是標准的。 -Werror將警告轉換為錯誤(這可能非常煩人,尤其是在沒有-Wno-unused-result情況下-Wno-unused-result編譯時)。 如果您使用 C99 功能, -pedanticstd=c89組合會給您額外的警告。

但僅此而已。 您不能將 C 編譯器調整為比 C 本身更節省類型的東西。

-M*系列選項。

這些讓你編寫 make 文件,自動找出你的 c 或 c++ 源文件應該依賴的頭文件。 GCC 將使用此依賴信息生成 make 文件,然后您從主 make 文件中包含它們。

這是一個使用 -MD 和 -MP 的極其通用的 makefile 示例,它將編譯一個充滿 c++ 源文件和頭文件的目錄,並自動找出所有依賴項:

CPPFLAGS += -MD -MP                                         
SRC = $(wildcard *.cpp)                                                       

my_executable: $(SRC:%.cpp=%.o)                                                        
        g++ $(LDFLAGS) -o $@ $^                                               

-include $(SRC:%.cpp=%.d)

這是一篇更深入討論它的博客文章: http : //www.microhowto.info/howto/automatically_generate_makefile_dependencies.html

我發現這個線程正在尋找一個標志來解決一個特定的問題,我在這里沒有看到它,所以我會在我的帖子中添加一個讓我難堪

-Wformat=2標志

-Wformat => 檢查對printfscanf等的調用,以確保提供的參數具有適合指定格式字符串的類型...

關於它的真正重要的部分( 根據 GCC 手冊):

-Wformat包含在-Wall 為了更好地控制格式檢查的某些方面,選項-Wformat-y2k -Wno-format-extra-args-Wno-format-extra-args-Wno-format-zero-length-Wformat-nonliteral-Wformat-security-Wformat=2可用,但不包含在 -Wall 中。`

所以,僅僅因為你擁有-Wall並不意味着你擁有一切。 ;)

-Wfloat-equal

來自: http : //mces.blogspot.com/2005/07/char-const-argv.html

我喜歡的其他新警告之一是 -Wfloat-equal。 每當您[擁有]處於相等條件的浮點數時,都會發出警告。 真是太棒了! 如果你每個人都編寫過計算機圖形或(更糟糕的:)計算幾何算法,你就會知道沒有兩個浮點數是相等的......

我有時將-s用於更小的可執行文件:

-s
    Remove all symbol table and relocation information from the executable.

來源: http : //gcc.gnu.org/onlinedocs/gcc/Link-Options.html#Link-Options

雖然這個答案可能有點偏離主題,但這個問題值得我 +1,因為

我對任何額外的警告和/或在某些情況下將警告轉化為錯誤特別感興趣,以絕對減少任何意外的類型不匹配。
有一個工具可以找出所有錯誤和可能不明顯的潛在錯誤,恕我直言,與 gcc 或任何其他編譯器相比,夾板在捕捉錯誤方面做得更好。 這是您工具箱中值得擁有的工具。

通過 lint 類型的工具(如夾板)進行靜態檢查應該是編譯器工具鏈的一部分。

我對任何其他警告特別感興趣,

除了-Wall-W-Wextra選項( -W適用於較舊版本的 gcc 以及較新版本;較新的版本支持替代名稱-Wextra ,這意味着相同的事情,但更具描述性)啟用各種附加警告。

還有更多警告,它們中的任何一個都沒有啟用,通常用於更可疑的事情。 可用選項集取決於您使用的 gcc 版本 - 有關詳細信息,請咨詢man gccinfo gcc ,或查看您感興趣的特定 gcc 版本的在線文檔-pedantic發出特定要求的所有警告正在使用標准(取決於其他選項,例如-std=xxx-ansi )並抱怨使用 gcc 擴展。

和/或在某些情況下將警告轉化為錯誤,以絕對減少任何意外的類型不匹配。

-Werror將所有警告變成錯誤。 不過,我認為 gcc 不允許您有選擇地針對特定警告執行此操作。

您可能會發現您必須在每個項目的基礎上選擇啟用哪些警告(特別是如果您使用-Werror ),因為來自外部庫的頭文件可能會絆倒其中的一些。 -pedantic我的經驗,尤其是-pedantic在這方面往往沒有幫助。)

  • -Wmissing-prototypes :如果在沒有先前原型聲明的情況下定義了全局函數。
  • -Wformat-security :警告使用代表可能的安全問題的格式函數。 目前,這會警告調用printfscanf函數,其中格式字符串不是字符串文字並且沒有格式參數
  • -Werror=return-type :當函數在 gcc 中沒有返回時強制執行錯誤。 它在 Visual Studio 中是/we4716

  • -Werror=implicit-function-declaration :在未定義/未包含的情況下使用函數時強制執行錯誤。 它是 Visual Studio 中的/we4013

  • -Werror=incompatible-pointer-types :當指針的類型與預期的指針類型不匹配時,Enfore 錯誤。 它是 Visual Studio 中的/we4133

實際上,我想保持我的 C 代碼跨平台,我使用 CMake,並將提供的 cflags 放入 CMakeLists.txt 中,例如:

if (CMAKE_SYSTEM_NAME MATCHES "Windows")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /we4013 /we4133 /we4716")
elseif (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Darwin")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=implicit-function-declaration -Werror=incompatible-pointer-types -Werror=return-type")
endif()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM