C的有用GCC标志


157

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

我对任何其他警告和/或在某些情况下将警告转换为错误以最大程度地减少任何意外的类型不匹配特别感兴趣。


9
好了-save-temps-Wshadow而且-fmudflap是我不知道的最伟大的发现,感谢所有。
马特·乔纳

据我所知,上下文是:运行gcc -c [flags-go-here] -o myprog.o myprog.c以编译(而非链接)C程序。
罗里·奥肯

Answers:


64

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

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

  • -fverbose-asm如果要进行编译-S以检查程序集输出,则很有用-它添加了一些有用的注释。

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


对于-ftrapv,请在这里看看stackoverflow.com/questions/20851061/… ..似乎有一个等待修复的错误。
Arjun Sreedharan 2015年

您可以检查以上评论吗?
Suraj Jain

-ftrapv实际上已由-fsanitize = signed-integer-overflow取代。
Marc Glisse

139

这是我的:

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

带有*的标记有时会给出过多的虚假警告,因此我会根据需要使用它们。


11
列表很完整,只想再添加一个;-Wformat=2:对printf / scanf功能进行额外的格式检查。
拍摄

1
所有这些暗示-Wall吗?
chacham15'9

2
@ chacham15,不,我不这么认为。 gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Alok Singhal 2012年

1
@Alok嗯,也许它不是发行版中的标准?我知道在我的Mbp上我必须明确关闭,-Wwrite-strings因为我非常讨厌它。
chacham15'9

@ chacham15,也许。但-Wwrite-strings具体描述是它不属于-Wallgcc.gnu.org/onlinedocs/gcc/…。也许您的设置中还有其他设置该标志的方法?还是您正在编译C ++?
Alok Singhal 2012年

52

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

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

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

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

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

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

-Wpointer-arith如果您的大多数便携式代码都无法使用,则此功能非常有用-pedantic


9
对于“ -Wfloat-equal”,如果项目上的开发人员不熟悉浮点数,则为+1;如果他们不熟悉浮点数,则为+。特别是它的后半部分。:-)
R .. GitHub停止帮助ICE,2010年

39
-save-temps

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

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

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


我确实想知道您是如何做到的...我一直只是问gcc是否需要转储该程序集。

35

令我惊讶的是-g,到目前为止还没有人说过-就我而言,最有用的标志是将调试信息放入可执行文件中,以便您可以调试它并遍历源代码(除非您精通并阅读了汇编和stepi程序执行时的命令)。


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

嗯,mudflap似乎很讨厌:P
马特·

9
-fmudflap从GCC 4.9开始不再支持warning: switch '-fmudflap' is no longer supported。它已由AddressSanitizer取代。
阿戈斯蒂诺

21

与C / C ++无关,但仍然很有用:

@file

将上面所有好的标记(您都已指定)放入“文件”中,并使用上面的标记将文件中的所有标记一起使用。

例如:

文件:编译器标记

-壁

-std = c99

-Wextra

然后编译:

gcc yourSourceFile @compilerFlags

15

-march=native 为要在其上编译的平台(=芯片)产生优化的代码


2
如果要针对不知道目标的非本机计算机进行编译,则可以使用mtune = xxx进行优化,而无需使用指令集。例如,mtune = generic与“平均”案例处理程序保持最新。
Turix 2012年

15

如果您需要了解编译器预定义的预处理器标志,请执行以下操作:

echo | gcc -E -dM -

13

它对检测错误并没有真正的帮助,但是很少提及的-masm=intel选项使-S检查装配输出变得非常好。

AT&T汇编语法太伤了我的头。


2
对我来说,AT&T和Intel之间的区别是C#和Java之间的区别。只是语法。都糟透了。:)
马特·乔纳

2
+1 @michael使gcc使用intel语法,而不是at&t的可怕之处。检查程序集使用足够的大脑周期-无需浪费src在操作码确定之前就需要的大脑周期。现在,如果仅gcc像其他编译器一样支持__asm {}内联,我们就一切就绪了!
6

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”的变量)。

是的,我是一个无可救药的乐观主义者,她一直想肯定现在某个平台将被宣布淘汰或获得一个不错的C ++编译器,我们终于可以切换到C ++了。在我看来,这是不可避免的-唯一的问题是这是在管理层最终向所有人发出小马之前还是之后。:-)


将其编写为C ++的好处是,我经常考虑这一点。(自然细分)
马特·乔纳

6
我应该指出,赞成C ++弃用C永远不会发生,对不起:)
Matt Joiner 2010年

4
考虑使用-o / dev / null代替rm -f junk
ulidtko 2011年

9
-Wstrict-prototypes -Wmissing-prototypes

10
并且,-Wold-style-definition如果您不得不与认为K&R样式函数是个好主意的累犯(即使使用原型声明)打交道,(我必须与那样的人打交道。当我找到用K&R编写的新代码时,这真的让我很烦。拥有不固定的旧K&R东西,但是有新代码,这很糟糕!很糟糕!!)
Jonathan Leffler

9

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

-Werror-implicit-function-declaration

在声明函数之前使用函数时,请给出错误。


8
man gcc

手册中充满了有趣的标志,并有很好的描述。但是,-Wall可能会使gcc尽可能详细。如果您想要更多有趣的数据,则应查看valgrind或其他用于检查错误的工具。


1
不过,它是loooooooooooooooooooooooooooooooooong。man gcc | nl报告超过11000条线。这不仅仅是臭名昭著的手册bash页!
2011年

12
谢天谢地,他们将其塞入了手册页,而不是那些令人讨厌的无法导航的“信息”页之一。
马特·乔纳

6

好吧,也-Wextra应该是标准的。-Werror将警告变成错误(这可能非常烦人,特别是如果您不使用进行编译-Wno-unused-result)。如果您使用C99功能,则-pedantic与结合使用std=c89会给您其他警告。

就是这样。您不能将C编译器调整为比C本身更节省类型的内容。


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


6

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


@Matt Joiner:由于您没有提及正在使用的计算机体系结构,因此您的gcc标志以及任何可能暗示的链接之间的标志可能会有所不同。这就是软件随附手册页的原因。
格雷格(Greg Hewgill)2010年

4

-Wfloat-equal

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

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


10
我知道自己在做什么,我的花车确实符合平等要求。
罗兰·伊利格

4

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

-Wformat=2标志

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

以及真正重要的部分(根据GCC手册):

-Wformat包含在中-Wall。在过去的检查中,选择格式的某些方面更多的控制-Wformat-y2k-Wno-format-extra-args-Wno-format-zero-length-Wformat-nonliteral-Wformat-security,和-Wformat=2可用,但不包括在-Wall.`

因此,仅仅因为拥有拥有权-Wall并不意味着拥有全部。;)


3

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

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

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


6
您应该只strip在二进制文件上运行,这样您就可以拥有一个带有调试信息的二进制文件,稍后将其删除以进行分发。
Hasturkun 2010年

是的,它strip-s可以工作,但可以更快,更轻松,尽管它不像运行时那么复杂strip
Vasiliy Sharapov 2010年

3

虽然这个答案可能有点题外话,但这个问题对我来说值得+1,因为

我对任何其他警告和/或在某些情况下将警告转换为错误以最大程度地减少任何意外的类型不匹配特别感兴趣。
有应该赶出来的工具所有的错误和潜在的错误,可能不是很明显,有夹板,其恕我直言,做一个更好的方式作业相比,海湾合作委员会或任何其他编译器为物拦截出错误。那是您的工具箱中值得拥有的工具。

通过诸如皮夹之类的绒毛类型的工具进行的静态检查应该已经属于编译器工具链的一部分。


它总是显示错误,无法在C:\ include中包含文件预处理器文件,我不确定该怎么办
Suraj Jain

2

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

除了之外-Wall-Wor -Wextra选项(-W适用于旧版本的gcc和较新版本的gcc;适用于gcc的替代名称-Wextra,这意味着同一件事,但更具描述性)支持各种其他警告。

甚至还有一些警告都没有启用,通常是针对更可疑的问题。可用选项集取决于您使用的gcc版本-请咨询man gccinfo gcc了解详细信息,或查看您感兴趣的特定gcc版本的在线文档。并-pedantic发出所使用的特定标准要求的所有警告(具体取决于在其他选项(例如-std=xxx-ansi)上,并抱怨使用gcc扩展名。

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

-Werror将所有警告变为错误。我不认为gcc可以让您有选择地针对特定警告进行操作。

您可能会发现必须对每个项目启用哪些警告(尤其是使用-Werror)进行选择,因为来自外部库的头文件可能会使其中一些警告失效。(-pedantic根据我的经验,这在这方面尤其无济于事。)


4
“不过,我认为gcc不会让您选择性地针对特定警告进行操作。” 实际上,您可以使用-Werror=some-warning
马修·弗拉申

0
  • -Wmissing-prototypes:如果在没有先前原型声明的情况下定义了全局函数。
  • -Wformat-security:警告使用代表可能的安全问题的格式功能。目前,这会警告有关在格式字符串不是字符串文字且没有格式参数的情况下对printfscanf函数的调用

0
  • -Werror=return-type:当函数在gcc中没有返回值时,强制执行错误。它/we4716在Visual Studio中。

  • -Werror=implicit-function-declaration:在未定义/未使用功能的情况下强制执行错误。它/we4013在Visual Studio中。

  • -Werror=incompatible-pointer-types:当指针的类型与预期的指针类型不匹配时,将发生Enfore错误。它/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()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.