使用GCC编译C程序的默认优化级别是-O0。 根据GCC文档关闭所有优化。 例如:
gcc -O0 test.c
但是,要检查-O0是否真的关闭所有优化。我执行了这个命令:
gcc -Q -O0 --help=optimizers
在这里,我有点惊讶。我启用了大约50个选项。 然后,我使用以下方法检查了传递给gcc的默认参数:
gcc -v
我明白了:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.4-
2ubuntu1~14.04' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --
enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --
program-suffix=-4.8 --enable-shared --enable-linker-build-id --
libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-
gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-
sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-
time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --
with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-
cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-
java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-
jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-
directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-
gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --
with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release
--build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04)
所以我的结论是我提供给程序的-O0
标志没有被其他东西覆盖。
事实上,我正在寻求从头开始实现一个生成随机优化选项序列的工具,并将生成的序列与默认级别0-3进行比较。就像“acovea”。所以,我想将我生成的序列与零优化级别(应该是-O0
)
你能解释一下为什么默认情况下-O0
启用了50个选项吗?
我想到的一个想法是使用-O0
进行编译,并使用-O0
50次在-fno-OPTIMIZATION_NAME
中关闭默认优化。你觉得怎么样?
答案 0 :(得分:15)
Stricto sensu,GCC编译器中端由优化传递的序列(实际上是嵌套树,在编译期间动态改变)构成,因此如果GCC没有进行优化,它将无法发出任何优化代码。
以另一种方式思考:GCC的输入语言非常丰富(即使对于普通的C,你有while
,for
,....)但是中间的Gimple语言很多更差(特别是Gimple / SSA)所以你需要应用一些转换从源AST转到Gimple。这些转换是优化通过,几乎按定义。
另请参阅answer和this中的图片(SVG图片),并阅读提及here的参考文献。
您应该将-O0
理解为禁用任何其他优化(例如由-O1
等提供...),而不需要生成某些可执行文件。
答案 1 :(得分:8)
好
gcc -O0 `gcc -Q -O0 --help=optimizers 2>&1 | perl -ane 'if ($F[1] =~/enabled/) {$F[0] =~ s/^\s*-f/-fno-/g;push @o,$F[0];}} END {print join(" ", @o)'` your args here
将关闭所有选项(哎呀)。
更严重的是,如果您要覆盖所有优化状态,请列出优化标记(无论如何需要执行此操作),并使用-fmyflag
或-fno-myflag
明确打开或关闭每个优化标记。 。这实质上回答了你的第二个问题。
但是,您可能会认为在关闭所有-O
级别的优化时不值得。
关于为什么它是这样的,它介于“太宽泛”之间。 (即你不得不问谁写了它)和'因为那是https://github.com/gcc-mirror/gcc/blob/master/gcc/toplev.c做的' 。
请注意,文档并未说-O0
禁用优化。它说(来自man page):
-O0
减少编译时间并使调试产生预期结果。这是默认值。
通过暗示,可能会有优化,不会增加编译时间,也不会影响调试,这些将保留。
答案 2 :(得分:3)
为了回答我的问题,我做了一些结论和假设:
所以让我说用O0编译并不意味着不会应用优化。减少编译时间并使调试更好的选项将打开,如@abligh所述。
换句话说,O0正在编译级别进行优化。生成的二进制文件未经过优化,以简化调试过程。
我举一个例子:此选项在O0级别启用
-faggressive - 环 - 优化
在GCC文件中:
此选项告诉循环优化器使用语言约束来派生循环迭代次数的边界。这假设循环代码不会通过例如导致有符号整数溢出或超出范围的数组访问来调用未定义的行为。循环迭代次数的界限用于指导循环展开和剥离以及循环退出测试优化。 默认情况下启用此选项。
因此对于GCC 4.8.x,默认情况下开启了近50个选项。