天天看点

不常见但是很有用的 GCC 命令行选项(二)

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 &lt;stdio.h&gt;</code>

<code>#include &lt;stdlib.h&gt;</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>&lt;</code>, <code>&lt;=</code>, <code>&gt;</code>, 或 <code>&gt;=</code> 比较

(仅 c++)一个枚举类型和一个非枚举类型同时出现在一个条件表达式中

(仅 c++)有歧义的虚拟基底

(仅 c++)寄存器类型的数组加下标

(仅 c++)对寄存器类型的变量进行取址

(仅 c++)基类没有在派生类的复制构建函数中进行初始化

下面是一段使用 <code>==</code> 运算符进行浮点值比较的代码:

<code>#include&lt;stdio.h&gt;</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&amp;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中国”

继续阅读