【问题标题】:are C functions declared in <c____> headers guaranteed to be in the global namespace as well as std?<c____> 头文件中声明的 C 函数是否保证在全局命名空间和 std 中?
【发布时间】:2011-02-04 22:59:37
【问题描述】:

所以这是我一直想知道但一直不太确定的事情。所以这完全是出于好奇,而不是真正的问题。

据我了解,当您执行 #include &lt;cstdlib&gt; 之类的操作时,所有内容(当然宏除外)都在 std:: 命名空间中声明。我见过的每个实现都是通过执行以下操作来实现的:

#include <stdlib.h>
namespace std {
    using ::abort;
    // etc....
}

这当然具有全局命名空间和std 中的效果。这种行为是否得到保证?还是有可能实现可以将这些东西放在std 中,但不能放在全局命名空间中?我能想到的唯一方法是让你的 libstdc++ 实现每个 c 函数本身,将它们直接放在 std 中,而不是仅仅包括现有的 libc 标头(因为没有从命名空间中删除某些内容的机制)。这当然是付出了很多努力,却几乎没有任何好处。

我的问题的本质是,以下程序是否严格符合并保证工作?

#include <cstdio>
int main() {
    ::printf("hello world\n");
}

编辑:我找到的最接近的是这个(17.4.1.2p4):

除非第 18 条至第 27、每个头cname的内容 应与 对应的头文件名.h,如 在 ISO/IEC 9899:1990 中规定 编程语言 C(第 7 条),或 ISO/IEC:1990 编程语言—C 修正案 1:C 完整性,(第 7 条), 视情况而定,就好像通过包含一样。在 然而,C++ 标准库, 声明和定义 (定义为的名称除外 C) 中的宏在命名空间内 命名空间标准的范围(3.3.5)。

说实话,我可以用任何一种方式解释。 “每个标头 cname 的内容应与相应标头 name.h 的内容相同,如 ISO/IEC 9899:1990 Programming Languages C 中所述”告诉我它们可能在全局命名空间中是必需的,但是“在但是,C++ 标准库的声明和定义(名称除外) 在 C 中定义为宏)在命名空间 std 的命名空间范围(3.3.5)内。”表示它们在 std 中(但没有指定它们所在的任何其他范围)。

【问题讨论】:

  • GCC 附带的 GNU 标头 #include 旧标头 within namespace std 声明,据我所知。
  • 至少某些版本的 STLPort4 确实只将函数带入 std 而不是全局命名空间。
  • 另请参阅 Red Hat 博客中 Jonathan Wakely 的 Why < cstdlib > is more complicated than you might think。 Wakely 是 GCC 的 C++ 标准库维护者之一。我认为&lt;math.h&gt; vs &lt;cmath&gt; 是一个更有趣的案例研究。

标签: c++ c namespaces


【解决方案1】:

下面是 MSVC 团队 (http://blogs.msdn.com/vcblog/archive/2008/08/28/the-mallocator.aspx#8904359) 的 Stephan T. Lavavej 对情况的一个很好的概要(与标准所说的相比有些相关性):

&gt;&lt;cstddef&gt;&lt;cstdlib&gt;,和std::size_t等都应该使用!

我以前对此非常小心。 C++98 有一个美好的梦想,&lt;cfoo&gt; 将在命名空间 std 中声明所有内容,&lt;foo.h&gt; 将包含&lt;cfoo&gt;,然后使用 using-declarations 将所有内容拖入全局命名空间。 (这是 D.5 [depr.c.headers]。)

许多实现者都忽略了这一点(其中一些实现者对 C 标准库头文件几乎没有控制权)。因此,C++0x 已被更改以匹配现实。从 N2723 工作文件 http://open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2723.pdf 开始,现在 &lt;cfoo&gt; 保证在命名空间 std 中声明所有内容,并且可能会或可能不会在全局命名空间中声明事物。 &lt;foo.h&gt; 则相反:它保证在全局命名空间中声明所有内容,并且可能会或可能不会在命名空间 std 中声明事物。

实际上,在 C++0x 中,包括 &lt;cfoo&gt; 并不能防止在全局命名空间中声明所有内容。这就是为什么我不再理会&lt;cfoo&gt;

这是图书馆第 456 期,http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#456

(C++0x 仍然弃用 C 标准库中的头文件,这很有趣。)

我自己从不喜欢&lt;cfoo&gt; 标头,但发现我一直使用&lt;foo.h&gt;。现在我觉得我可以不再为我在这方面缺乏 C++“纯度”而焦虑了。

【讨论】:

  • +1。我猜不同的人有不同的笔画。就我个人而言,我发现“c”比“.h”更不烦人:)
  • 令人着迷,感谢您指出这一点。我一直很喜欢&lt;cfoo&gt; 的外观,但没看到写std::size_tsize_t 更能吸引我,所以写了后者,并隐约担心在遥远的未来有一天会被不再工作的事情所吸引.我觉得我的#include 风格在不久的将来会重新调整......
  • “我自己从来不喜欢&lt;cfoo&gt;这个头文件,发现我一直用&lt;foo.h&gt;...” - 你是怎么做的例如,&lt;math.h&gt;abslog 以及缺少的重载?我已经看到丢失的重载会破坏编译。
  • @jww 你很幸运得到了编译错误。我被 gcc 的特殊性所困扰,例如std::sqrt(long double) 存在于&lt;cmath&gt; 中,而::sqrt(long double) 不存在,而std::sqrt(double)::sqrt(double) 都存在——因此如果你写错了sqrt(myLongDoubleVar),调用::sqrt(double) 会丢失精度没有任何警告,即使是-Wall -Wextra。同时,如果包含&lt;math.h&gt;,则所有重载都存在于全局命名空间中。
  • @Ruslan - 另请参阅 Red Hat 博客中 Jonathan Wakely 的 Why &lt;cstdlib&gt; is more complicated than you might think。 Wakely 是 GCC 的 C++ 标准库维护者之一。
【解决方案2】:

目前,没有。事实上,即使代码可以与我现在使用的每个编译器一起使用,它也确实应该工作 - #includeing 其中一个 c* 标头只应该让您访问到命名空间 std 内的名称。

由于实现这一点非常痛苦(要做到这一点,基本上需要将整个 C 库复制为正确命名空间中的 C++ 库),在 C++ 0x 中,他们稍微改变了要求——你的代码现在是 允许工作,但(至少如果没有记错的话)它仍然不需要工作。

【讨论】:

  • 但是库头允许包含其他库头,这似乎允许全局范围内的名称,不是吗?
  • @Ben:我不这么认为。具体措辞是(第 17.4.4/1 节):“C++ 标头可能包含其他 C++ 标头。”然而,根据 §D.5/1:“为了与标准 C 库兼容,C++ 标准库提供了 18 个 C 头文件……”。由于它们被专门称为“C 标头”而不是“C++ 标头”,因此我认为它们不属于该许可范围(但我可以看到很容易不同意的地方)。
【解决方案3】:

我不能代表标准,因为我没有读过它们,但是可以设想一个 C++ 环境,它不是建立在 C 环境之上的,或者 C 环境是底层 C++ API 之上的兼容层.在这种情况下,可能无法做出这些保证。如果禁止这样的实现成为合规实现,我会感到惊讶。

【讨论】:

  • 确实如此,但它可能要求效果相同(本质上要求此类标头在命名空间块之后具有适当的using std::xxxx; 声明,以便手动将它们放入全局命名空间中)。
猜你喜欢
  • 2017-05-31
  • 2019-10-29
  • 1970-01-01
  • 2015-12-12
  • 2016-06-11
  • 1970-01-01
  • 2018-07-24
  • 2013-08-16
相关资源
最近更新 更多