使用g++编译时,默认采用哪个C++标准?

106

我有一段代码,它长得像下面这样。假设它在一个名为 example.cpp 的文件中。

#include <fstream>
#include <string> // line added after edit for clarity

int main() {
    std::string filename = "input.txt";
    std::ifstream in(filename);

    return 0;
}
在Windows系统上,如果我在cmd中输入g++ example.cpp命令,编译会失败。我认为大部分是由于链接器抱怨无法将string转换为const char*引起的一长串错误。
但如果我使用附加参数运行编译器,像这样:g++ -std=c++17 example.cpp,它将能够编译并正常工作,没有任何问题。
当我运行前一条命令时会发生什么?我猜测会调用C++编译器的默认标准版本,但我不知道是哪一个?作为程序员/开发人员,我是否应该始终使用带有额外参数的后者?

5
取决于您的gcc版本。 - πάντα ῥεῖ
3
咳嗽声@给踩负分的人们:这并不像你们想象的那么明显,而且这个问题写得很好,有一个漂亮(虽然不可移植)的例子。 - Bathsheba
1
我认为-std会改变编译器的语义,而不是运行完全不同的编译器。您对编译器(“gcc” vs “clang” vs ...)或编译器尝试遵守的标准(“C++17” vs “C++11” vs ...)感兴趣吗? - gmatht
@gmatht 后者确实是我想知道的。我猜我误解了像“-std=c++11”这样的命令参数,认为它执行了一个完全独立的编译器。 - Manuel
10个回答

119

如果您的g++版本高于4.7,那么您可以通过以下方式找到支持的默认C++标准版本:

g++ -dM -E -x c++  /dev/null | grep -F __cplusplus

我的机器上的一个例子:

mburr@mint17 ~ $ g++ --version | head -1
g++ (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
mburr@mint17 ~ $ g++ -dM -E -x c++  /dev/null | grep -F __cplusplus
#define __cplusplus 199711L

一些参考资料:


1
看起来做到了!我的一分建议是,当您指定-std=...选项时,它确实会更改该值。 - ϹοδεMεδιϲ
@Michael,请添加链接,其中cplusplus的结果与标准匹配: https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html - Paulo Neves
9
嘿,迈克尔,你能解释一下 199711L 是什么意思吗?请翻译。 - Rishabh Agrahari
对我来说可以运行,结果是#define __cplusplus 201402L - Georg
太好了。正如人们所期望的那样,它也适用于clang和C语言:clang -dM -E -x c /dev/null | grep -F __STDC_VERSION__ - akhan
2
@RishabhAgrahari 如果想要了解__cplusplus的解释,请参考以下链接:https://dev59.com/d2gu5IYBdhLWcg3w0aOg - keineahnung2345

33

g++ 的 man 页面实际上告诉了 C++ 代码的默认标准。

使用以下脚本显示相关部分:

man g++ | col -b | grep -B 2 -e '-std=.* This is the default'
例如,在RHEL 6中,g++(GCC)4.4.7 20120313(Red Hat 4.4.7-23)的输出结果为:
         gnu++98
           GNU dialect of -std=c++98.  This is the default for C++ code.

在Fedora 28中,使用g++ (GCC) 8.1.1 20180502 (Red Hat 8.1.1-1)编译的程序输出:

       gnu++14
       gnu++1y
           GNU dialect of -std=c++14.  This is the default for C++ code.  The name gnu++1y is deprecated.

4
这取决于gcc和其文档之间的一致性,但对于g++ 12.2.1无效。手册中说默认值是C++17,但实际上是C++20。 - zkoza

27

您还可以使用gdb进行检查

  1. $ g++ example.cpp -g 使用-g标志编译程序以生成调试信息
  2. $ gdb a.out 使用gdb调试程序
  3. (gdb) b main 在主函数处设置断点
  4. (gdb) run 运行程序(将在断点处暂停)
  5. (gdb) info source

会打印出类似以下的内容:

Current source file is example.cpp
Compilation directory is /home/xxx/cpp
Located in /home/xxx/cpp/example.cpp
Contains 7 lines.
Source language is c++.
Producer is GNU C++14 6.3.0 20170516 -mtune=generic -march=x86-64 -g.
Compiled with DWARF 2 debugging format.
Does not include preprocessor macro info.

编译器使用的标准是:Producer is GNU C++14

如果您重新使用-std=c++11编译程序(例如),gdb会检测到:Producer is GNU C++11


16

我认为通过查看man页面就可以了解(至少对于g ++而言):

-std的描述下,man页面列出了所有的C++标准,包括GNU方言。在一个特定的标准下,有一个不显眼的声明,这是C++代码的默认值。(对于C标准也有类似的声明: 这是C代码的默认值。

例如,对于g ++ / gcc 5.4.0版本,这是在gnu ++ 98 / gnu ++ 03下列出的,而对于g ++ / gcc版本6.4.0,则列在gnu ++ 14下。


15

我猜测会调用C++编译器的默认版本,但我不知道是哪个版本?

只有阅读您特定编译器版本的文档才能猜测。

如果使用较新的GCC,建议首先了解您正在使用的版本,方法是运行:

g++ -v
或者
g++ --version

接着参考特定版本的GCC版本,例如对于GCC 7,阅读GCC 7 changes

或者运行

g++ -dumpspecs

并解密默认的所谓 规格文件

顺便提一下,您可以通过编写代码(例如在某些常用头文件中)来确保C++至少是C++17。

 #if __cplusplus < 201412L
 #error expecting C++17 standard
 #endif

我实际上建议这样做。

顺便说一下,把C++98和C++17视为两种不同的语言(例如,像Ocaml4和C++11那样)。要求用户使用支持某个定义的语言标准的编译器(例如C++11),而不是某个特定版本的GCC。还可以阅读有关软件包管理器的信息。


2
你引用的 GCC 7 变更 的哪一部分提到了如果未指定 -std=xxx,则哪个 -std=xxx 选项是默认值? - DodgyCodeException
GCC编译器文档的每个版本都明确说明了C和C++的默认语言标准,无需猜测。请参见下面的答案。 - MikeOnline

10

如果您正在使用GCC编译器,您可以在手册页上找到它:

man g++ | grep "This is the default for C++ code"


6
在命令行中输入g++ --version可以显示编译器版本,从中您可以推断出默认标准。因此,您无法直接确定,但可以通过一些努力来推断它。
编译器应该定义__cplusplus,可以在编译时使用它来提取它们声称实现的标准;但是,许多编译器尚未实现这一点。
(不要忘记包括您需要的所有C++标准库头文件:例如std::string的头文件在哪里?不要依赖于C++标准库实现自动包含其他头文件 - 这样做不是编写可移植性强的C++代码。)

3
因为g++ --version仅显示 GCC 编译器的版本,而非默认标准的版本,所以是错误的。请注意保持原意并将语言更通俗易懂,不提供额外解释或其他内容。 - Basile Starynkevitch
2
@Manuel,你不应该依赖于那个。始终从标准库中#include你所使用的内容。 - πάντα ῥεῖ
1
是的,但有额外的间接性。 - Basile Starynkevitch
1
@πάνταῥεῖ 谢谢,已经注意到了。另外,输入 g++ --version 只会告诉我 g++ 的版本,而不会说它使用的默认“-std=c++”是什么。 - Manuel
1
抱歉,我以为“--version”不会直接返回所使用的标准,现在已经明确了。;-) - Bathsheba
显示剩余3条评论

4

你的代码将与符合C++11及以上标准的编译器(和相关库)编译通过。

原因是C++11引入了一个接受const std::string&std::ifstream构造函数。在C++11之前,无法传递std::string,因此在代码中需要传递filename.c_str()而不是filename

根据来自gnu的信息,https://gcc.gnu.org/projects/cxx-status.html#cxx11,gcc.4.8.1是第一个完全支持C++11的版本。在命令行上使用g++ -v将提示g++告诉您它的版本号。

如果您深入文档,可能会找到最初支持足够特性从而使您的代码(如所给)可以编译的版本/子版本。但这样的版本将支持一些C++11的功能而不支持其他功能。

由于Windows没有预装g++,因此您将拥有某个人(您自己?)选择安装的版本。您的Windows版本中不会关联任何默认版本的g++。


这是正确的,但更像是一条长而有用的评论,而不是对原问题的真正回答。 - Basile Starynkevitch

2
默认的C和C++语言标准在GCC手册中有详细说明。您可以按照以下步骤找到它们:
1. 浏览至https://gcc.gnu.org/onlinedocs/ 2. 选择您感兴趣的GCC版本的GCC #.## Manual链接,例如对于GCC 7.5.0:
https://gcc.gnu.org/onlinedocs/gcc-7.5.0/gcc/ 3. 单击主题链接Language Standards Supported by GCC,然后单击C++ Language(或C language)主题。这两个主题都会有类似以下句子的内容:

The default, if no C++ language dialect options are given, is -std=gnu++14.

The default, if no C language dialect options are given, is -std=gnu11.

以上两个示例是针对GCC 7.5.0的。

2
当我运行前面的命令时会发生什么?我猜想会调用C++编译器的默认版本标准,但我不知道是哪个?
当您运行g++而没有指定要使用的C++语言标准时,它将使用在未指定时决定为默认值的标准。
GCC使用的默认C++语言标准取决于您正在使用的GCC版本。请参见GCC的C++语言支持状态文档,在撰写本文时,该文档说明如下:
C++17功能自GCC 5以来可用。这种模式是GCC 11的默认模式;可以使用-std=c++17命令行标志或-std=gnu++17同时启用GNU扩展来明确选择它。
GCC完全支持2014年C++标准。这种模式是GCC 6.1到GCC 10(包括)的默认模式;可以使用-std=c++14命令行标志或-std=gnu++14同时启用GNU扩展来明确选择它。
GCC完全支持1998年C++标准,该标准由2003年技术勘误和一些后续缺陷报告进行了修改,但不包括后来从语言中删除的导出特性。在GCC 6.1之前的版本中,这是默认模式;可以使用-std=c++98命令行标志或-std=gnu++98以启用GNU扩展来显式选择此模式。
如果您还对其他编译器的语言/标准库支持感兴趣,您可以查看Clang的C++支持文档cppreference.com的编译器支持页面
作为一名程序员/开发者,我是否应该始终使用带有额外参数的后一个命令?
我不确定你是否“应该”,但显而易见的是,如果你想/需要使用特定语言标准,除非你要/需要使用的标准恰好是你正在使用的GCC版本的默认值,否则你将需要使用它。

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