【问题标题】:Why does g++ 4.9.0 have std::isnan by default?为什么 g++ 4.9.0 默认有 std::isnan?
【发布时间】:2017-11-11 21:06:54
【问题描述】:

我的理解是函数std::isnan 只能从 C++11 开始使用。此外,g++ 使用 -std=gnu++98,除非明确告知不要这样做。

那么为什么会编译呢?

>> cat test.cpp
#include <cmath>
int main(int argc, char** argv)
{
    return std::isnan(0);
}

>> g++ test.cpp

是否有标志可以将函数从&lt;cmath&gt; 中取出?

【问题讨论】:

  • 可能是自 it exists in C99 以来的扩展。如果使用-pedantic 编译会发生什么?
  • @NathanOliver 它仍然与-pedantic 一起编译。如果它使用 C99 宏,它不应该在全局命名空间中吗?
  • 这些 C 宏实际上是按照 C++ 标准 (see this answer) 作为函数实现的。有趣的是,即使在带有 -std=c++98 的 gcc 4.4.7 中,您也会在程序集中看到 __gnu_cxx::__enable_if&lt;std::__is_arithmetic&lt;int&gt;::__value, int&gt;::__type std::isnan&lt;int&gt;(int)

标签: c++ c++11 g++ g++4.9


【解决方案1】:

这是一个长期存在的问题,已记录在 in the FAQ 中,但您不一定能够理解。

4.3. _XOPEN_SOURCE_GNU_SOURCE 总是被定义?

在 Solaris 上,g++(但不是 gcc)总是定义预处理器宏 _XOPEN_SOURCE。在 GNU/Linux 上,_GNU_SOURCE 也是如此。 (这不是一个详尽的列表;其他宏和其他平台也会受到影响。)

这些宏通常用在 C 库头文件中,保护新版本的函数免受旧版本的影响。 C++98 标准库包括 C 标准库,但它需要 C90 版本,出于向后兼容的原因,这通常不是许多供应商的默认设置。

更重要的是,C++ 标准要求在定义某些符号后仅在某些平台上可用的行为。通常问题涉及与 I/O 相关的 typedef。为了确保正确性,编译器只预先定义了这些符号。

请注意,仅在构建库时(在安装期间)#define 是不够的。由于我们没有“export”关键字,因此库中的大部分内容都以标头形式存在,这意味着在解析和编译程序时也必须定义符号。

要查看定义了哪些符号,请在目标的 gcc 配置标头中查找 CPLUSPLUS_CPP_SPEC(并尝试更改它们以查看在构建复杂代码时会发生什么)。您还可以运行 g++ -E -dM - /null" [sic] 以显示任何特定安装的预定义宏列表。

这已在邮件列表quite a bit 上讨论过。

这种方法有点鸡肋。我们想找到一个更清洁的解决方案,但还没有人投入时间。

解释一下:

glibc 是提供标准 C 库的东西。它支持多种模式。

它支持各种严格的 C 模式和严格的 POSIX 模式。在这些模式中,当仅包含标准头文件时,只有标准功能可用。在 C90 模式下,这不包括 isnan

支持多种扩展方式。在这些模式下,也可以使用非标准功能。在 C90 + 扩展模式下,这包括 isnan_GNU_SOURCE 预处理器宏是启用所有扩展的宏。

libstdc++ 提供标准 C++ 库。它对 glibc 的要求比严格的 C90 模式提供的更多。因此,只有两种选择:要么 libstdc++ 不提供它无法提供的那些标准 C++ 功能,要么 libstdc++ 即使在严格的 ANSI 模式下也强制启用 glibc 的扩展。两者都意味着不符合 C++ 标准,但前者限制了特性,而后者提供了它们。后者被视为较小的邪恶。

解决这个问题的唯一合理方法是 glibc 提供一些非标准的方式来访问其扩展,即使在严格的 ANSI 模式下也是如此。尚不存在这种方式,在创建这种方式之前,即使在本应成为标准的 C++ 编译模式下,非标准名称也将可用。

【讨论】:

    【解决方案2】:

    编译器开发人员懒于完全删除应该仅在下一版本标准中可用的每个功能,尤其是当相关库 (C99) 同时具有这些功能时。

    实用程序(验证您的代码实际上是否符合特定标准)不足以让编译器编写者非常努力地让他们的编译器提供该服务。

    相反,通常会在特定的标准标志下实现新功能。有时它们会意外地向后移植。当标准最终确定时,部分实现会存在一段时间,直到它变得足够好。

    然后开始制定标准的下一个版本。下一个版本标志会为您提供一个不太稳定的开发环境,因为新功能会被尝试、丢弃和更改。

    它付出了一些努力来不向后移植东西,但它不是一个展示者。

    【讨论】:

    • 基本上就是这样。无论您使用哪种编译器,如果您希望它严格遵守特定的语言标准,您都会感到失望。
    • 这些函数先于它们添加到标准中。它们以各种形式的存在预示着标准。 VC2010 和 gcc 4.6 有这些。但是其他编译器或不同平台的名称不同,例如在 Solaris 上,它直到 C++11 才成为 std 命名空间的一部分,后来它只是重新导入命名空间,因此标准符号和非标准符号都存在。标准不否认向后兼容或扩展
    • @Swift 正如预言的那样,std::isnan 将会是。
    猜你喜欢
    • 2020-10-30
    • 2021-07-14
    • 2018-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-27
    • 1970-01-01
    • 2021-04-03
    相关资源
    最近更新 更多