gcc 选项 std=gnu++17 与 std=c++17

gcc option std=gnu++17 vs std=c++17

我在使用带有 -std=gnu++17 的 g++(我试过版本 8 到 11)时遇到编译错误,但可以使用选项 -std=c++17.

编译相同的代码
#include <complex.h>
int main()
{
    int I=0;
    return I;
}

使用选项 -std=gnu++17,这会导致以下错误:

error: invalid cast from type '__complex__ float' to type 'int'
    5 |     int I=0;

使用选项 -std=c++17 编译时没有警告和错误。

我知道在complex.hheader里面有一个宏定义#define I _Complex_I。 gcc 文档说选项 -std=gnu++17 添加了相应 c++ 标准的 GNU 方言。尽管如此,我还是不明白为什么这会导致上述程序的编译出现差异。

背景: 当我开始使用 cmake 特性 cxx_std_17 时遇到了这种行为,它添加了标志 std=gnu++17 并导致各种编译错误,因为一个第三方库使用标识符 I 而另一个包含 header complex.h.

您可以通过简单地从具有不同标准设置的预处理器中获取结果来自己找出差异,如下所示:

 g++ -std=gnu++17 main.cpp -E > gnu
 g++ -std=c++17 main.cpp -E > std

diff 文件。

根本原因是,文件 /usr/include/complex.h 只有在未设置 __STRICT_ANSI__ 的情况下才会被使用。通过使用 gnu 扩展,这个宏没有被设置。您可以在文件 /usr/include/c++/11/complex.h

中看到选择

您的头文件的安装路径可能不同,但我相信您可以将给定的信息与您的库安装相匹配。

一般而言,I 不应在 C++ 中定义,但如果正在使用 gnu 扩展,则应如此。提示是:不要使用此类扩展,因为它们可能会使您的代码与其他编译器不兼容。

很明显,如果 I 被定义为“某物”,您的代码将中断,并且会导致任何不是有效变量名的东西。

C++ 标准说:(C++17 C.6.1/3):

The C++ headers <ccomplex> (D.4.1) and <ctgmath> (D.4.4), as well as their corresponding C headers <complex.h> and <tgmath.h>, do not contain any of the content from the C standard library and instead merely include other headers from the C++ standard library.

所以 C 的 complex.h 不包含在 C++ 中,这意味着在您的代码中 I 不应该被定义为任何东西。

当允许 GNU 扩展时,GCC 确实将 C 内容作为扩展包含在内。见 PR 82417:

As an extension the C++ version of <complex.h> includes the C version, but that defines macros with non-reserved names that should not be defined in ISO C++. Only include the C header for non-strict modes, or for pre-C++11 (because C++98 doesn't mention <complex.h> at all).