C的有用GCC标志

除了设置-Wall和设置-std=XXX ,还有哪些其他真正有用的,但较less知道的编译器标志在C中有用?

我特别感兴趣的任何额外的警告,和/或在某些情况下将警告转为错误,以绝对减less任何意外types的不匹配。

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

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

  • -fverbose-asm在编译时使用-S来检查程序集输出是非常有用的,它增加了一些信息量的评论。

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

这是我的:

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

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

总是使用-O或以上( -O1-O2-Os等)。 在默认的优化级别上,gcc的编译速度非常快,并且没有做足够的分析来警告像单元化variables这样的事情。

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

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

包含在-Wextra警告倾向于标记常见的合法代码。 它们可能对代码评论很有用(尽pipelint风格的程序发现更多的陷阱更加灵活),但是我不会为了正常的开发而打开它们。

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

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

-Wpointer-arith是非常有用的,如果你有大部分可移植的代码,不适用于-pedantic

 -save-temps 

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

预处理源对于debuggingmacros很有用。

该程序集对于确定哪些优化已生效很有用。 例如,你可能想要validationGCC是否对某些recursion函数进行了尾部调用优化,因为没有它你可能会溢出堆栈。

我很惊讶没有人这样说过 – 就我而言,最有用的标志是-g ,它将debugging信息放入可执行文件中,以便您可以debugging它并逐步执行源代码(除非您精通并阅读组装和类似stepi命令)的程序,而它正在执行。

-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 

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

这对于检测错误并不是很有帮助,但是很less提到的-masm=intel选项使得使用-S来检查程序集输出更好,更好。

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

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

 echo | gcc -E -dM - 

不是真的与C / C ++有关,但是非常有用:

 @file 

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

例如:

文件:compilerFlags

-壁

-std = C99

-Wextra

然后编译:

 gcc yourSourceFile @compilerFlags 

我的makefile通常包含

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

以上讨论过这些选项中最重要的,所以我将指出尚未指出的两个特征:

尽pipe我正在研究一个需要简单的C语言的代码库,但是仍然没有像样的C ++编译器,所以我使用C ++编译器(除了C编译器)进行“额外”编译。 这有三个好处:

  1. C ++编译器偶尔会给我提供比C​​编译器更好的警告消息。
  2. C ++编译器接受-Weffc ++选项,偶尔给我一些有用的提示,如果我只用普通的C语言编译,我会错过的。
  3. 我可以保持代码相对容易移植到C ++,避免了普通C代码无效的C ++代码(如定义名为“bool”的variables)的一些边界条件。

是的,我是一个毫无希望乐观的波莉安娜(Pollyanna),他一直坚持认为,现在任何一个月都会宣布一个平台会被淘汰,或者得到一个体面的C ++编译器,我们终于可以切换到C ++。 在我看来,这是不可避免的 – 唯一的问题是,pipe理层在pipe理层之前还是之后最终发布每个人都是小马。 🙂

 -Wstrict-prototypes -Wmissing-prototypes 

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

 -Werror-implicit-function-declaration 

在声明之前使用函数时发生错误。

 man gcc 

手册中充满了有趣的标志和很好的描述。 但是,墙可能会使gcc尽可能详细。 如果你想要更有趣的数据,你应该看看Valgrind或其他工具来检查错误。

那么, -Wextra应该是标准的。 -Werror将警告转化为错误(这可能非常烦人,特别是如果您编译时没有-Wno-unused-result )。 如果您使用C99function,则与std=c89结合使用可以提供额外的警告。

但是这是关于它的。 您不能将C编译器调整为比C本身更省的types保存。

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

-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

-Wfloat-equal

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

我喜欢的其他新警告之一就是“平等”。 只要你在平等条件下有一个浮点数就会发出警告。 这是光明的! 如果你有每一个编程计算机graphics或(更糟:)的计算几何algorithm,你知道没有两个浮动匹配平等…

我有时使用-s来创build一个更小的可执行文件:

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

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

虽然这个答案可能有点偏离主题,因此,这个问题是值得我+1

我特别感兴趣的任何额外的警告,和/或在某些情况下将警告转为错误,以绝对减less任何意外types的不匹配。

有一个工具,应该赶上所有的错误和潜在的错误,可能不是很明显,有藤条 ,恕我直言更好地发现错误相比,海湾合作委员会或任何其他编译器的事情。 这是在你的工具箱里有一个值得的工具。

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

我发现这个线程寻找一个标志来解决一个具体的问题,我没有在这里看到它,所以我会添加一个只是在我的post上绊倒我:

-Wformat=2标志

-Wformat =>检查对printfscanf等的调用,以确保提供的参数具有与指定的格式string相适应的types…

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

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

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

我特别感兴趣的任何额外的警告,

-Wall-W-Wextra选项( -W适用于旧版本的gcc以及更新的版本;更新的版本支持替代名称-Wextra ,意思是相同的,但更具描述性)启用各种额外的警告。

还有更多的警告,这些警告都不是由这两者中的任何一个所启用的,一般来说,这些警告更糟糕。 可用选项的集合取决于您正在使用的gcc版本 – 请参阅man gccinfo gcc以获取详细信息,或者查看您感兴趣的特定gcc版本的在线文档 。标准正在使用(这取决于其他选项,如-std=xxx-ansi ),并抱怨使用gcc扩展。

和/或在某些情况下将警告转换为错误,以绝对地将任何意外的types不匹配最小化。

-Werror将所有警告转化为错误。 不过,我不认为gcc可以让你select性地做特别的警告。

你可能会发现,你必须有select性地在每个项目的基础上启用哪些警告(特别是如果你使用-Werror ),因为来自外部库的头文件可以-Werror其中的一些。 (在我的经验中,特别是在这方面特别容易-pedantic 。)