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编译器)进行“额外”编译。 这有三个好处:
- C ++编译器偶尔会给我提供比C编译器更好的警告消息。
- C ++编译器接受-Weffc ++选项,偶尔给我一些有用的提示,如果我只用普通的C语言编译,我会错过的。
- 我可以保持代码相对容易移植到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
=>检查对printf
和scanf
等的调用,以确保提供的参数具有与指定的格式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 gcc
或info gcc
以获取详细信息,或者查看您感兴趣的特定gcc版本的在线文档 。标准正在使用(这取决于其他选项,如-std=xxx
或-ansi
),并抱怨使用gcc扩展。
和/或在某些情况下将警告转换为错误,以绝对地将任何意外的types不匹配最小化。
-Werror
将所有警告转化为错误。 不过,我不认为gcc可以让你select性地做特别的警告。
你可能会发现,你必须有select性地在每个项目的基础上启用哪些警告(特别是如果你使用-Werror
),因为来自外部库的头文件可以-Werror
其中的一些。 (在我的经验中,特别是在这方面特别容易-pedantic
。)