不常見但是很有用的 GCC 命令行選項(二)

2021-02-19 Linux中國
編譯自: https://www.howtoforge.com/tutorial/uncommon-but-useful-gcc-command-line-options-2/ 
作者: Ansh
譯者: ucasFL

gcc 編譯器提供了幾乎數不清的命令行選項列表。當然,沒有人會使用過或者精通它所有的命令行選項,但是有一些命令行選項是每一個 gcc 用戶都應該知道的 - 即使不是必須知道。它們中有一些很常用,其他一些不太常用,但不常用並不意味著它們的用處沒前者大。

在這個系列的文章中,我們集中於一些不常用但是很有用的 gcc 命令行選項,在第一節已經講到幾個這樣的命令行選項。

不知道你是否能夠回想起,在這個系列教程的第一部分的開始,我簡要的提到了開發者們通常用來生成警告的 -Wall 選項,並不包括一些特殊的警告。如果你不了解這些特殊警告,並且不知道如何生成它們,不用擔心,我將在這篇文章中詳細講解關於它們所有的細節。

除此以外,這篇文章也將涉及與浮點值相關的 gcc 警告選項,以及在 gcc 命令行選項列表變得很大的時候如何更好的管理它們。

在繼續之前,請記住,這個教程中的所有例子、命令和指令都已在 Ubuntu 16.04 LTS 作業系統和 gcc 5.4.0 上測試過。

生成 -Wall 選項不包括的警告

儘管 gcc 編譯器的 -Wall 選項涵蓋了絕大多數警告標記,依然有一些警告不能生成。為了生成它們,請使用 -Wextra 選項。

比如,下面的代碼:

#include <stdio.h>

#include <stdlib.h>

int main()

{

   int i=0;

   /* ...

      some code here

      ...

   */

   if(i);

       return 1;

    return 0;

}

我不小心在 if 條件後面多打了一個分號。現在,如果使用下面的 gcc 命令來進行編譯,不會生成任何警告。

gcc -Wall test.c -o test

但是如果同時使用 -Wextra 選項來進行編譯:

gcc -Wall -Wextra test.c -o test

會生成下面這樣一個警告:

test.c: In function 『main』:

test.c:10:8: warning: suggest braces around empty body in an 『if』 statement [-Wempty-body]

if(i);

從上面的警告清楚的看到, -Wextra 選項從內部啟用了 -Wempty-body 選項,從而可以檢測可疑代碼並生成警告。下面是這個選項啟用的全部警告標記。

-Wclobbered

-Wempty-body

-Wignored-qualifiers

-Wmissing-field-initializers

-Wmissing-parameter-type (僅針對 C 語言)

-Wold-style-declaration (僅針對 C 語言)

-Woverride-init

-Wsign-compare

-Wtype-limits

-Wuninitialized

-Wunused-parameter (只有和 -Wunused 或 -Wall 選項使用時才會啟用)

-Wunused-but-set-parameter (只有和-Wunused或-Wall` 選項使用時才會生成)

如果想對上面所提到的標記有更進一步的了解,請查看 gcc 手冊[1]。

此外,遇到下面這些情況, -Wextra 選項也會生成警告:

一個指針和整數 0 進行 <, <=, >, 或 >= 比較

(僅 C++)一個枚舉類型和一個非枚舉類型同時出現在一個條件表達式中

(僅 C++)有歧義的虛擬基底

(僅 C++)寄存器類型的數組加下標

(僅 C++)對寄存器類型的變量進行取址

(僅 C++)基類沒有在派生類的複製構建函數中進行初始化

浮點值的等值比較時生成警告

你可能已經知道,浮點值不能進行確切的相等比較(如果不知道,請閱讀與浮點值比較相關的 FAQ[2])。但是如果你不小心這樣做了, gcc 編譯器是否會報出錯誤或警告?讓我們來測試一下:

下面是一段使用 == 運算符進行浮點值比較的代碼:

#include<stdio.h>

void compare(float x, float y)

{

   if(x == y)

   {

       printf("\n EQUAL \n");

   }

}

int main(void)

{

   compare(1.234, 1.56789);

   return 0;

}

使用下面的 gcc 命令(包含 -Wall 和 -Wextra 選項)來編譯這段代碼:

gcc -Wall -Wextra test.c -o test

遺憾的是,上面的命令沒有生成任何與浮點值比較相關的警告。快速看一下 gcc 手冊,在這種情形下可以使用一個專用的 -Wfloat-equal 選項。

下面是包含這個選項的命令:

gcc -Wall -Wextra -Wfloat-equal test.c -o test

下面是這條命令產生的輸出:

test.c: In function 『compare』:

test.c:5:10: warning: comparing floating point with == or != is unsafe [-Wfloat-equal]

if(x == y)

正如上面你所看到的輸出那樣, -Wfloat-equal 選項會強制 gcc 編譯器生成一個與浮點值比較相關的警告。

這兒是gcc 手冊[3]關於這一選項的說明:

這背後的想法是,有時,對程式設計師來說,把浮點值考慮成近似無限精確的實數是方便的。如果你這樣做,那麼你需要通過分析代碼,或者其他方式,算出這種計算方式引入的最大或可能的最大誤差,然後進行比較時(以及產生輸出時,不過這是一個不同的問題)允許這個誤差。特別要指出,不應該檢查是否相等,而應該檢查兩個值是否可能出現範圍重疊;這是用關係運算符來做的,所以等值比較可能是搞錯了。

如何更好的管理 gcc 命令行選項

如果在你使用的 gcc 命令中,命令行選項列表變得很大而且很難管理,那麼你可以把它放在一個文本文件中,然後把文件名作為 gcc 命令的一個參數。之後,你必須使用 @file 命令行選項。

比如,下面這行是你的 gcc 命令:

gcc -Wall -Wextra -Wfloat-equal test.c -o test

然後你可以把這三個和警告相關的選項放到一個文件裡,文件名叫做 gcc-options:

$ cat gcc-options&nbsp;

-Wall -Wextra -Wfloat-equal

這樣,你的 gcc 命令會變得更加簡潔並且易於管理:

gcc @gcc-options test.c -o test

下面是 gcc 手冊關於 @file 的說明:

從文件中讀取命令行選項。讀取到的選項隨之被插入到原始 @file 選項所在的位置。如果文件不存在或者無法讀取,那麼這個選項就會被當成文字處理,而不會被刪除。

文件中的選項以空格分隔。選項中包含空白字符的話,可以用一個由單引號或雙引號包圍完整選項。任何字符(包括反斜槓: '\')均可能通過一個 '\' 前綴而包含在一個選項中。如果該文件本身包含額外的 @file 選項,那麼它將會被遞歸處理。

結論

在這個系列的教程中,我們一共講解了 5 個不常見但是很有用的 gcc 命令行選項: -Save-temps、-g、 -Wextra、-Wfloat-equal 以及 @file。記得花時間練習使用每一個選項,同時不要忘了瀏覽 gcc 手冊上面所提供的關於它們的全部細節。

你是否知道或使用其他像這樣有用的 gcc 命令行選項,並希望把它們在全世界範圍內分享?請在下面的評論區留下所有的細節。

via: https://www.howtoforge.com/tutorial/uncommon-but-useful-gcc-command-line-options-2/

作者:Ansh[4] 譯者:ucasFL 校對:jasminepeng

本文由 LCTT[5] 原創編譯,Linux中國 榮譽推出

[1]: https://linux.die.net/man/1/gcc
[2]: https://isocpp.org/wiki/faq/newbie
[3]: https://linux.die.net/man/1/gcc
[4]: https://twitter.com/howtoforgecom
[5]: https://github.com/LCTT/TranslateProject

相關焦點

  • 不常見但是很有用的 gcc 命令行選項(一)
    公正地講,這並不是設計上的錯誤,因為每個用戶都會有自己的需求,他們只在他們的領域內使用該工具。然而,深入了解你所使用的工具也是很有益處的,因為你永遠不知道它的某個功能會在什麼時候派上用場,從而節省下你寶貴的時間。舉一個例子:編譯器。一個優秀的程式語言編譯器總是會提供極多的選項,但是用戶一般只知道和使用其中很有限的一部分功能。
  • Linux GCC 常用命令
    2.1預處理gcc -E test.c -o test.i 或 gcc -E test.c可以輸出test.i文件中存放著test.c經預處理之後的代碼。打開test.i文件,看一看,就明白了。後面那條指令,是直接在命令行窗口中輸出預處理後的代碼.gcc的-E選項,可以讓編譯器在預處理後停止,並輸出預處理結果。
  • Linux GCC常用命令
    2.1 預處理gcc -E test.c -o test.i 或 gcc -E test.c 可以輸出test.i文件中存放著test.c經預處理之後的代碼。打開test.i文件,看一看,就明白了。後面那條指令,是直接在命令行窗口中輸出預處理後的代碼。
  • 詳解命令-GCC
    ;-S:將C代碼轉換為彙編代碼;-wall:顯示警告信息;-c:僅執行編譯操作,不進行連接操作。實例常用編譯命令選項假設源程序文件名為test.c無選項編譯連結gcc test.c將test.c預處理、彙編、編譯並連結形成可執行文件。這裡未指定輸出文件,默認輸出為a.out。
  • Linux GCC簡明教程(使用GCC編寫C語言程序)
    微軟的 Visual Studio 也支持 Linux 了,在 Windows 下用慣了 Visual Studio 的用戶也可以毫無障礙地遷移到 Linux 平臺。但是作為初學者,我建議大家在命令行模式下編譯C語言程序,這樣能夠了解生成一個可執行程序的詳細步驟,以及編譯命令的各種設置選項,為以後的 Linux C/C++ 開發打好堅實的基礎。
  • gcc、arm-linux-gcc和arm-elf-gcc的關係?
    一個常見的例子是在 PC 機上為運行在基於 ARM、PowerPC或 MIPS 的目標機的編譯軟體。幸運的是,GCC 使得這一過程所面臨的困難要比聽起來小得多。GCC 中的一般工具通常都是通過在命令行上調用命令(如 gcc)來執行的。在使用交叉編譯的情況下,這些工具將根據它編譯的目標而命名。
  • Linux應用編程之GCC常用編譯選項
    上一小節我們簡單的演示了一下gcc如何生成可執行文件,然而整個編譯過程並不是很明朗,於是這裡小哥就之前介紹的編譯流程圖通過GCC的編譯選項來逐步進行分解介紹:    GCC的 -E 選項實現源文件到.i文件的預編譯處理過程 : 主要用於處理一些帶有#的代碼等,比如宏#define、條件編譯#if,#endif、#pragma;同時也包括注釋的剔除,
  • 【Linux公開課】gcc編譯控制選項
    10.1.4 gcc編譯控制選項 前面已經講過,gcc的基本用法是:$ gcc [選項] [文件名] gcc後很多編譯控制選項,使得gcc可以根據不同的參數進行不同的編譯處理,可供gcc調用的參數大約有100來個,但實際使用中,並不會用到這麼多選項和參數。
  • 嵌入式Linux下最常用的C語言編譯器GCC命令詳解
    比如:一個工程有main.c foo.c def.c生成foo的可執行文件。編譯命令如下:$ gcc –c main.c foo.c def.c –o foo或者:$ gcc –o foo main.c foo.c def.c三.庫依賴函數庫是一些頭文件(.h)和庫文件(.so或者.a)的集合。
  • 如何優雅地處理命令行參數?
    前言我們在Linux用到的命令常常支持很多參數,那麼如何寫一個程序,也像Linux命令一樣支持很多參數呢?有什麼什麼優雅的處理方法?命令行參數在介紹如何處理命令行參數之前,簡單介紹一下命令行參數,已經了解的朋友可以跳過此小節。
  • gcc&arm-linux-gcc編譯過程詳解
    老規矩,文字無法完整描述視頻內容,如果覺得這些文章對你有用,想進一步學習更深層次的乾貨,請訪問100ask.taobao.com購買arm裸機1期加強版視頻課程。第1節_gcc編譯器1_常用選項_編譯過程詳解gcc的使用方法gcc [選項] 文件名gcc常用選項 一個c/c++文件要經過預處理、編譯、彙編和連結才能變成可執行文件。
  • 用 Plumbum 開發 Python 命令行工具
    Python 腳本一般使用 optparse 或者最新的 argparse 及其衍生品來開發命令行工具,但是所有這些表現力有限,而且非常不直觀(甚至不夠 Pythonic)。Plumbum 的 CLI 工具包提供了一個程序化的方法來構建命令行應用程式,不需要創建一個解析器對象,然後填充一系列「選項」,該 CLI 工具包使用內省機制將這些原語轉義成 Pythonic 結構。
  • Python 命令行之旅:深入 argparse(二)
    若你仍在使用 Python 2,請注意兩者之間語法和庫的使用差異哦~幫助 自動生成幫助當你在命令行程序中指定 -h 或 --help 參數時,都會輸出幫助信息。而 argparse 可通過指定 add_help 入參為 True 或不指定,以達到自動輸出幫助信息的目的。
  • 【Linux公開課】gcc基本使用
    10.1.3 gcc基本使用 gcc最基本的用法是∶$ gcc [選項] [文件名] 下面以hello.c的編譯為例,初步了解一下gcc的基本用法:1.編譯hello.c 在當前目錄下創建hello目錄並進入,用Vi編輯器創建一個hello.c文件
  • Bash Shell腳本中命令行選項/參數的使用
    Bash Shell腳本中命令行選項/參數的使用 0.引言寫程序的時候經常要處理命令行參數,本文描述在Bash下的命令行處理方式。--prefix我們稱之為一個長選項,即選項本身多於一個字符,它也需要一個參數,用等號連接,當然等號不是必須的,/home可以直接寫在--prefix後面,即--prefix/home,更多的限制後面具體會講到。 在bash中,可以用以下三種方式來處理命令行參數,每種方式都有自己的應用場景。
  • 《Linux 命令行》中文版
    微處理器的發明,使普通老百姓(就如你和我)真正擁有一臺計算機成為可能。今天, 人們難以想像,只有大企業和強大的政府才能夠擁有計算機的世界,是怎樣的一個世界。 簡單說,你做不了多少事情。今天,世界已經截然不同了。計算機遍布各個領域,從小手錶到大型數據中心,及大小介於它們之間的每件東西。 除了隨處可見的計算機之外,我們還有一個無處不在的連接所有計算機的網絡。
  • 全面認識GCC編譯器及工作流程
    雖然 GNU 計劃在開發免費作業系統上不成功,但是卻成功開發幾個廣為流傳的 GNU 軟體,其中最著名的是 GNU C Complier(gcc)。GCC 不僅支持C的許多「方言」,也可以區別不同的C語言標準;也就是說,可以使用命令行選項來控制編譯器在翻譯原始碼時應該遵循哪個C標準。GCC 編譯器在編譯一個C語言程序時需要經過以下 4 步:將C語言源程序預處理,生成.i文件。預處理後的.i文件編譯成為彙編語言,生成.s文件。將彙編語言文件經過彙編,生成目標文件.o文件。
  • gcc和g++是什麼,有什麼區別?
    很簡單,GCC 編譯器已經為我們提供了調用它的接口,對於 C 語言或者 C++ 程序,可以通過執行 gcc 或者 g++ 指令來調用 GCC 編譯器。值得一提的是,實際使用中我們更習慣使用 gcc 指令編譯 C 語言程序,用 g++ 指令編譯 C++ 代碼。
  • C語言編譯器之一,GCC
    C語言作為高級語言,用其編寫的程序指令機器並不能識別,因此需要有一個編譯器將其轉換為機器可識別的二進位指令。
  • gcc和g++有什麼區別?
    很簡單,GCC 編譯器已經為我們提供了調用它的接口,對於 C 語言或者 C++ 程序,可以通過執行 gcc 或者 g++ 指令來調用 GCC 編譯器。值得一提的是,實際使用中我們更習慣使用 gcc 指令編譯 C 語言程序,用 g++ 指令編譯 C++ 代碼。