C的有用GCC标志

时间:2010-07-30 22:04:21

标签: c gcc compiler-flags

除了设置-Wall和设置-std=XXX之外,还有哪些其他真正有用但不太知名的编译器标志可用于C?

我对任何其他警告特别感兴趣,并且/或者在某些情况下将警告变成错误,以绝对最小化任何意外类型不匹配。

24 个答案:

答案 0 :(得分:132)

这是我的:

  • -Wextra-Wall:必不可少。
  • -Wfloat-equal:很有用,因为通常测试浮点数是否相等是不好的。
  • -Wundef:警告是否在#if指令中评估了未初始化的标识符。
  • -Wshadow:当局部变量影响另一个局部变量,参数或全局变量时,或者每当内置函数被遮蔽时,都会发出警告。
  • -Wpointer-arith:警告是否有任何内容取决于函数或void的大小。
  • -Wcast-align:每当指针被投射时发出警告,以便增加目标的所需对齐。例如,警告是否char *强制转换为机器上的int *,只能在两个或四个字节的边界访问整数。
  • -Wstrict-prototypes:如果声明或定义了函数而未指定参数类型,则发出警告。
  • -Wstrict-overflow=5:警告编译器根据未发生签名溢出的假设进行优化的情况。 (值5可能过于严格,请参见手册页。)
  • -Wwrite-strings:为字符串常量提供类型const char[ length ],以便将一个地址复制到非const char *指针中得到警告。
  • -Waggregate-return:警告是否定义或调用了返回结构或联合的任何函数。
  • -Wcast-qual:每当指针被强制转换为从目标类型 * 中删除类型限定符时发出警告。
  • -Wswitch-default:当switch语句没有default案例 * 时发出警告。
  • -Wswitch-enum:警告只要switch语句的枚举类型为索引,并且该枚举的一个或多个命名代码缺少case *
  • -Wconversion:警告可能会改变值 * 的隐式转换。
  • -Wunreachable-code:警告编译器是否检测到代码永远不会执行 *

那些标记为 * 的人有时会发出太多的虚假警告,所以我会根据需要使用它们。

答案 1 :(得分:63)

有几个-f代码生成选项很有趣:

  • -ftrapv函数将导致程序在有符号整数溢出时中止(在C中正式为“未定义的行为”)。

  • 如果您使用-fverbose-asm进行编译来检查程序集输出,则
  • -S非常有用 - 它会添加一些信息性的注释。

  • -finstrument-functions添加代码以在每个函数入口和出口点调用用户提供的分析函数。

答案 2 :(得分:50)

始终使用-O或以上(-O1-O2-Os等)。在默认的优化级别,gcc用于编译速度,并且没有做足够的分析来警告像整合变量这样的事情。

考虑制定-Werror政策,因为不会停止编辑的警告会被忽略。

-Wall几乎打开很可能是错误的警告。

-Wextra中包含的警告往往会标记常见的合法代码。它们可能对代码审查很有用(虽然lint风格的程序发现更多的陷阱更灵活),但我不打算将它们用于正常开发。

如果项目的开发人员不熟悉浮点数,那么

-Wfloat-equal是一个好主意,如果不熟悉浮点数,那就不错了。

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

如果您的大多数便携式代码不能与-Wpointer-arith一起使用,则

-pedantic非常有用。

答案 3 :(得分:37)

-save-temps

这会留下预处理器和程序集的结果。

预处理源对调试宏非常有用。

该程序集对于确定哪些优化生效非常有用。例如,您可能想要验证GCC是否在某些递归函数上进行尾调用优化,因为没有它,您可能会溢出堆栈。

答案 4 :(得分:35)

我很惊讶没有人说过这个 - 就我而言,最有用的标志是-g,它将调试信息放入可执行文件中,以便您可以调试它并逐步完成源代码(除非你正在执行的程序中,你精通并阅读程序集,就像程序的stepi命令一样。

答案 5 :(得分:35)

-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

答案 6 :(得分:19)

与C / C ++并不真正相关,但无论如何都很有用:

@file

将所有上述好的标记(你已经指定了)放在'文件'中,并使用上面的标志一起使用该文件中的所有标记。

例如:

文件:compilerFlags

  

-Wall

     

-std = C99

     

-Wextra

然后编译:

gcc yourSourceFile @compilerFlags

答案 7 :(得分:15)

-march=native为您正在编译的平台(=芯片)生成优化代码

答案 8 :(得分:13)

如果您需要知道编译器预定义的预处理器标志:

echo | gcc -E -dM -

答案 9 :(得分:13)

检测错误并没有什么帮助,但是很少提到的-masm=intel选项使得使用-S来检查程序集输出更多,更好。

AT&amp; T汇编语法对我的影响太大了。

答案 10 :(得分:10)

我的makefile通常包含

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

之前已讨论过这些选项中最重要的选项,因此我将指出尚未指出的两个功能:

即使我正在开发一个需要的代码库,因为它可以移植到某些平台,而仍然没有像样的C ++编译器,我做了一个“额外的“使用C ++编译器编译(除了C编译器)。这有三个好处:

  1. C ++编译器偶尔会给我提供比C​​编译器更好的警告消息。
  2. C ++编译器接受-Weffc ++选项,它偶尔会给我一些有用的提示,如果我只在简单的C中编译它,我会错过这些提示。
  3. 我可以保持代码相对容易移植到C ++,避免一些边界条件,其中普通C代码是无效的C ++代码(例如定义名为“bool”的变量)。
  4. 是的,我是一个绝望乐观的Pollyanna,一直认为肯定现在任何一个平台要么被宣布为过时,要么获得一个像样的C ++编译器,我们终于可以切换到C ++ 。在我看来,这是不可避免的 - 唯一的问题是,在管理层最终发布每个人都是小马之前或之后是否会发生这种情况。 : - )

答案 11 :(得分:9)

-Wstrict-prototypes -Wmissing-prototypes

答案 12 :(得分:9)

这是一个尚未提及的伟大旗帜:

-Werror-implicit-function-declaration

在声明之前,只要使用函数就会出错。

答案 13 :(得分:8)

man gcc

手册中充满了有趣的标志和良好的描述。但是,-Wall可能会使gcc尽可能冗长。如果您想要更多有趣的数据,您应该查看valgrind或其他一些工具来检查错误。

答案 14 :(得分:6)

-Werror,它将所有警告视为错误并停止编译。 gcc manual page解释了编译器的每个命令行开关。

答案 15 :(得分:6)

-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

答案 16 :(得分:6)

嗯,-Wextra也应该是标准的。 -Werror将警告变为错误(可能非常令人讨厌,尤其是在没有-Wno-unused-result的情况下进行编译时)。如果您使用C99功能,则-pedanticstd=c89结合使用可为您提供其他警告。

但那是关于它的。你不能将C编译器调整为比C本身更类型的保存。

答案 17 :(得分:4)

-Wfloat-equal

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

  

我喜欢的另一个新警告是-Wfloat-equal。只要你在平等条件下有一个浮点数,那就会发出警告。那很有魅力!如果你有每个编程的计算机图形或(更糟糕的)计算几何算法,你知道没有两个浮点数与平等相匹配......

答案 18 :(得分:4)

我发现这个帖子正在寻找一个标志来修复一个特定的问题,我没有在这里看到它所以我会添加一个只是让我感到困扰my post

-Wformat=2标志

  

-Wformat =&gt;检查对printfscanf等的调用,以确保提供的参数具有适合指定格式字符串的类型...

关于它的真正重要部分(according to the GCC manual):

  

-Wformat包含在-Wall中。要更好地控制格式检查的某些方面,可以使用选项-Wformat-y2k-Wno-format-extra-args-Wno-format-zero-length-Wformat-nonliteral-Wformat-security-Wformat=2 ,但不包括在-Wall。

所以,仅仅因为你有-Wall并不意味着你拥有它。 ;)

答案 19 :(得分:3)

虽然这个答案可能稍微偏离主题,但这个问题对我来说是值得的+1,因为

我对任何其他警告特别感兴趣,和/或将警告变成错误有些情况可以绝对地减少任何意外的类型不匹配。
有一个工具可以识别所有错误和可能不明显的潜在错误,有splint恕我直言与gcc或任何其他编译器相比,在捕获错误方面做得更好。这是你工具箱中值得拥有的工具。

通过lint类型的工具(如splint)进行静态检查应该是编译器工具链的一部分。

答案 20 :(得分:3)

我有时会使用-s来获得更小的可执行文件:

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

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

答案 21 :(得分:2)

  

我对任何其他警告特别感兴趣,

除了-Wall之外,-W-Wextra选项(-W适用于较早版本的gcc以及较新版本;较新版本支持备用名称-Wextra,这意味着相同的事情,但更具描述性)可以启用各种其他警告。

还有更多警告,其中任何一个都没有启用,通常用于更糟糕的事情。可用选项集取决于您使用的gcc版本 - 有关详细信息,请参阅man gccinfo gcc,或查看您感兴趣的特定gcc版本的online documentation-pedantic会发出所使用的特定标准所需的所有警告(这取决于其他选项,例如-std=xxx-ansi),并抱怨使用gcc扩展程序。

  

和/或在某些情况下将警告变为错误,以绝对最小化任何意外类型   错配。

-Werror将所有警告变为错误。我不认为gcc会让你有选择地为特定警告做这件事。

您可能会发现必须选择在每个项目的基础上启用哪些警告(特别是如果您使用-Werror),因为来自外部库的头文件可能会使其中的某些文件发生错误。 (根据我的经验,(-pedantic在这方面尤其无益。)

答案 22 :(得分:0)

  • -Wmissing-prototypes:如果定义的全局函数没有先前的原型声明。
  • -Wformat-security:警告使用表示可能出现的安全问题的格式函数。目前,这会警告调用printfscanf函数,其中格式字符串不是字符串文字,并且没有格式参数

答案 23 :(得分:0)

  • -Werror=return-type:在gcc中函数未返回时强制执行错误。在Visual Studio中为/we4716

  • -Werror=implicit-function-declaration:在使用功能时未定义/未包含时强制执行错误。在Visual Studio中为/we4013

  • -Werror=incompatible-pointer-types:当指针的类型与预期的指针类型不匹配时,将发生错误。在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()