168

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

我对任何额外的警告和/或在某些情况下将警告变成错误特别感兴趣,以绝对减少任何意外的类型不匹配。

4

24 回答 24

149

这是我的:

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

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

于 2010-07-31T02:10:52.043 回答
69

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

  • -fverbose-asm如果您正在编译-S以检查程序集输出,这很有用 - 它添加了一些信息性注释。

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

  • --coverage检测程序中的分支和调用,并创建一个覆盖注释文件,以便在程序运行时生成覆盖数据,该数据可由gcov程序格式化以帮助分析测试覆盖。

  • -fsanitize={address,thread,undefined}分别启用 AddressSanitizer、ThreadSanitizer 和 UndefinedBehaviorSanitizer 代码清理程序。这些检测程序以在运行时检查各种错误。

之前也提到过这个答案-ftrapv,但是这个功能已经被它所取代,-fsanitize=signed-integer-overflow它是由-fsanitize=undefined.

于 2010-07-31T01:35:14.280 回答
56

始终使用-O或以上(-O1-O2-Os等)。在默认优化级别,gcc 会提高编译速度,并且不会进行足够的分析来警告诸如未初始化变量之类的事情。

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

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

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

-Wfloat-equal如果项目的开发人员不熟悉浮点,这是一个好主意,如果他们不熟悉,则是个坏主意。

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

-Wpointer-arith如果您的大部分可移植代码不适用于-pedantic.

于 2010-07-30T22:29:27.863 回答
41
-save-temps

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

预处理的源代码对于调试宏很有用。

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

于 2010-08-03T18:58:32.407 回答
40

我很惊讶还没有人这么说 - 就我而言,最有用的标志是-g将调试信息放入可执行文件中,以便您可以调试它并逐步查看源代码(除非您精通并阅读汇编和就像stepi程序的命令),而它正在执行。

于 2010-07-30T22:23:27.970 回答
36

-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
于 2010-08-03T18:50:33.377 回答
25

与 C/C++ 没有真正的关系,但无论如何都很有用:

@file

将上述所有好的标志(你们都指定)放在一个“文件”中,并使用上面的这个标志来一起使用该文件中的所有标志。

例如:

文件:编译器标志

-墙

-std=c99

-Wextra

然后编译:

gcc yourSourceFile @compilerFlags
于 2013-07-15T06:47:00.537 回答
17

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

于 2010-07-31T07:33:17.000 回答
16

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

echo | gcc -E -dM -
于 2010-07-31T13:46:59.863 回答
15

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

AT&T 汇编语法对我的伤害太大了。

于 2010-08-04T06:15:31.440 回答
11

这是一个没有被提及的伟大旗帜:

-Werror-implicit-function-declaration

每当在声明之前使用函数时都会给出错误。

于 2010-08-14T15:59:57.047 回答
10

我的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++。在我看来,这是不可避免的——唯一的问题是这发生在管理层最终给每个人发小马之前还是之后。:-)

于 2010-08-13T21:33:51.073 回答
9
-Wstrict-prototypes -Wmissing-prototypes
于 2010-07-30T22:32:46.927 回答
8
man gcc

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

于 2010-07-30T22:09:07.273 回答
7

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

于 2010-07-30T22:09:18.147 回答
6

-M*选项系列。

这些使您可以编写自动确定您的 c 或 c++ 源文件应该依赖的头文件的 make 文件。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

于 2012-01-06T21:47:37.700 回答
6

嗯,-Wextra也应该是标准的。-Werror将警告变成错误(这可能烦人,特别是如果您编译时没有-Wno-unused-result. -pedantic如果您使用 C99 功能,则结合使用std=c89会给您额外的警告。

但仅此而已。您不能将 C 编译器调整为比 C 本身更节省类型的东西。

于 2010-07-30T22:14:04.287 回答
5

我发现这个线程正在寻找一个标志来解决特定问题,我在这里看不到它,所以我将添加一个只是让我在我的帖子中难倒的问题:

-Wformat=2国旗_

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

关于它的真正重要的部分(根据 GCC 手册):

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

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

于 2012-10-25T12:56:54.833 回答
4

-Wfloat-equal

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

我喜欢的其他新警告之一是 -Wfloat-equal。每当您在相等条件下[有]一个浮点数时,都会发出警告。这太棒了!如果您每个人都编写了计算机图形或(更糟糕的:)计算几何算法,您就会知道没有两个浮点数与相等性匹配......

于 2010-07-31T13:06:29.867 回答
4

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

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

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

于 2010-07-31T00:38:41.947 回答
3

虽然这个答案可能有点偏离主题,而且这个问题对我来说是值得 +1 的,因为

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

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

于 2010-08-09T15:04:13.033 回答
2

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

除了-Wall-Wor-Wextra选项(-W适用于较旧版本的 gcc 以及较新的 gcc;较新的版本支持替代名称-Wextra,这意味着相同的东西,但更具描述性)启用各种附加警告。

还有更多的警告没有被其中任何一个启用,通常是针对更可疑的坏事。可用选项集取决于您使用的 gcc 版本 - 请咨询man gccinfo gcc了解详细信息,或查看您感兴趣的特定 gcc 版本的在线文档-pedantic。并发出正在使用的特定标准所需的所有警告(这取决于在其他选项上,例如-std=xxxor -ansi) 并抱怨使用 gcc 扩展。

和/或在某些情况下将警告变成错误,以绝对减少任何意外的类型不匹配。

-Werror将所有警告变成错误。不过,我认为 gcc 不允许您有选择地针对特定警告执行此操作。

您可能会发现您必须选择基于每个项目启用哪些警告(特别是如果您使用-Werror),因为来自外部库的头文件可能会触发其中一些警告。(-pedantic根据我的经验,尤其是在这方面往往没有帮助。)

于 2010-07-30T22:10:05.873 回答
1
  • -Wmissing-prototypes: 如果定义了全局函数而没有先前的原型声明。
  • -Wformat-security: 警告使用可能存在安全问题的格式函数。目前,这会警告格式字符串不是字符串文字且没有格式参数的调用printf和函数scanf
于 2018-02-07T09:35:07.177 回答
1
  • -Werror=return-type: 当函数在 gcc 中没有返回时执行错误。它/we4716在 Visual Studio 中。

  • -Werror=implicit-function-declaration:在使用未定义/未包含的函数时执行错误。它/we4013在 Visual Studio 中。

  • -Werror=incompatible-pointer-types: 当指针的类型与预期的指针类型不匹配时会出现错误。它/we4133在 Visual Studio 中。

实际上,我想保持我的 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()
于 2018-11-27T11:05:32.767 回答