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

Passing multiple -std switches to g++

假设 运行 g++

是否安全
g++ -std=c++98 -std=c++11 ...

将使用 C++11 进行编译吗?我没有在 documentation 中找到明确的确认,但我看到 -O 标志是这样的。

GCC manual 没有说明 指定的任何互斥 -std=... 选项中的最后一个生效。第一次出现 或最后一次出现是唯一的选择。有无数的 GCC 标志从有限集中采用相互排斥的替代值 - 相互 排他性的,至少对翻译单元的语言取模。我们简称为 mutex options。 记录上次设置生效似乎是随机的罕见情况。这是 正如您所指出的那样,针对 -O 选项进行了记录,并且通常用于互斥警告选项,也许 其他。从未记录过 first 的 multiple 设置生效,因为 这从来都不是真的。

文档倾向于 - 不完全一致 - 历史惯例 类 unix 操作系统中的命令用法。如果命令接受互斥选项 然后最后一次出现的选项生效。如果命令是 - 不寻常的 - 只对第一次出现的选项采取行动,那么这将是一个错误 完全接受后续事件的命令:它应该给出使用错误。

这是习俗和惯例。该习惯有助于使用以下工具编写脚本 尊重它,例如脚本可以调用传递一些默认设置的工具 mutex 选项,但允许用户通过脚本的参数覆盖该设置, 其值可以简单地附加到默认调用。

如果没有你想要的官方 GCC 文档,你可能会得到 通过尝试找到它不适用的任何 GCC 互斥选项来保证 最后一次发生生效的情况。这是一击:

我将编译 link 这个程序:

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

垃圾暴露的bug-1713064076没有被诊断出来是因为 -Wno-format,不是-Wformat,生效了。

它是 64 位的,不是 32 位的 executable:

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

已优化 -O1,而非 -O0,因为:

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

说明局部符号str不在符号table中。

并且不包含任何调试信息:

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

根据 -g0,而不是 -g3

既然GCC是开源软件,另一种解惑方式 关于 C 程序员可用的行为,至少, 是检查相关的源代码,可通过 git source-control 获得 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++11OPT_std_c__11 - 并且毫无疑问它 使 -std 选项设置生效,而不管之前的设置是什么。您可以查看 master 以外的分支 (gcc-{5|6|7}-branch) 结论相同

依赖于有效性的 GCC 构建系统脚本并不少见 通过附加新设置覆盖选项设置。从法律上讲,这 通常指望未记录的行为,但有更好的 俄罗斯加入北约的可能性大于海湾合作委员会停止采取最后设定的可能性 它解析互斥选项。