将多个-std开关传递给g++

10
可以假设使用g++运行是安全的,这与您的操作系统和环境变量设置有关。
g++ -std=c++98 -std=c++11 ...

使用C++11编译会有影响吗?我在文档中没有找到明确的确认,但是我看到-O标志表现出这种方式。
1个回答

19

GCC手册没有说明任何互斥的-std=...选项中最后一个会生效。第一次出现或最后一次出现是唯一的选择。有许多GCC标志需要从有限集合中采取互斥的替代值,至少在翻译单元的语言模块方面是互斥的。简称为mutex选项。似乎很少有文档记录最后一个设置会生效。你已经注意到了,对于-O选项进行了记录,并且通常以一般术语记录互斥警告选项,也许还有其他选项。从未记录多个设置的第一次会生效,因为这是不正确的。

文档倾向于使用unix-likes OSes命令用法的历史惯例,但不完全一致。如果一个命令接受mutex选项,则该选项的最后一次出现生效。如果该命令非常不寻常地仅作用于选项的第一次出现,则该命令接受后续出现实际上会是错误的:它应该给出使用错误。

这是一种惯例。该惯例有助于使用尊重它的工具进行脚本编写,例如,脚本可以调用一个工具并传递某个互斥选项的默认设置,但允许用户通过脚本参数覆盖该设置,其值可以简单地附加到默认调用中。
如果没有您想要的官方GCC文档,则可以尝试查找任何GCC互斥选项,其中不是最后出现的选项生效。以下是一个尝试:
我将编译和链接此程序:

main.cpp

#include <cstdio>

#if __cplusplus >= 201103L 
static const char * str = "C++11";
#else
static const char * str = "Not C++11";
#endif

int main() 
{
    printf("%s\n%d\n",str,str); // Format `%d` for `str` mismatch
    return 0;
} 

使用命令行:

g++ -std=c++98 -std=c++11 -m32 -m64 -O0 -O1 -g3 -g0 \
-Wformat -Wno-format -o wrong -o right main.cpp

请求矛盾的选项对:

  • -std=c++98 -std=c++11:符合C++98。符合C++11。
  • -m32 -m64:生成32位代码。生成64位代码。
  • -O0 -O1:不进行任何优化。优化到1级。
  • -g3 -g0:发出最大的调试信息。不发出调试信息。
  • -Wformat -Wno-format。检查printf参数是否正确。不检查它们。
  • -o wrong -o right。输出程序wrong。输出程序right

它成功构建,没有诊断:

$ echo "[$(g++ -std=c++98 -std=c++11 -m32 -m64 -O0 -O1 -g3 -g0 \
-Wformat -Wno-format -o wrong -o right main.cpp 2>&1)]"
[]

它不输出程序 wrong

$ ./wrong
bash: ./wrong: No such file or directory

它确实输出了一个程序right

$ ./right
C++11
-1713064076

这告诉我们它是用C++11编译的,而不是C++98

由垃圾-1713064076暴露出的错误没有被诊断,因为生效的是-Wno-format而不是-Wformat

这是一个64位可执行文件,而不是32位的:

$ file right
right: ELF 64-bit LSB shared object, x86-64 ...

它被优化为-O1,而不是-O0,因为:

$ "[$(nm -C right | grep str)]"
[]

显示本地符号str不在符号表中。

并且它不包含调试信息:

echo "[$(readelf --debug-dump right)]"
[]

根据-g0,而不是-g3
由于GCC是开源软件,至少对于C程序员来说,解决对其行为的疑虑的另一种方法是检查相关的源代码,可通过git源代码控制在https://github.com/gcc-mirror/gcc获取。
您问题的相关源代码位于文件gcc/gcc/c-family/c-opts.c中的函数。
/* Handle switch SCODE with argument ARG.  VALUE is true, unless no-
   form of an -f or -W option was given.  Returns false if the switch was
   invalid, true if valid.  Use HANDLERS in recursive handle_option calls.  */
bool
c_common_handle_option (size_t scode, const char *arg, int value,
            int kind, location_t loc,
            const struct cl_option_handlers *handlers);

这本质上是一个简单的开关阶梯,枚举了scode的选项设置——对于选项-std=c++11,它是OPT_std_c__11——并且毫不含糊地表明,它会将一个-std选项设置放入到先前生效的任何设置中。你可以查看除了master之外的其他分支(gcc-{5|6|7}-branch),得出相同的结论。

在GCC构建系统脚本中,经常会发现依赖于通过附加新设置来覆盖选项设置的有效性。法律上,这通常依靠未记录的行为,但是GCC取最后解析的互斥选项设置的设置的可能性比俄罗斯加入北约更大。


感谢您提供如此详细的解释和示例。 - krlmlr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接