【问题标题】:Should I include stddef.h or cstddef for size_t我应该为 size_t 包含 stddef.h 还是 cstddef
【发布时间】:2011-07-02 01:09:25
【问题描述】:

当我想在 C++ 中使用size_t 时,我应该包含<stddef.h> 还是<cstddef>?我听几个人说<cstddef> 是个坏主意,应该弃用。这是为什么呢?

【问题讨论】:

标签: c++ namespaces naming-conventions header-files size-t


【解决方案1】:

stddef.h 是 C 标头。名称 size_t 在其中的全局命名空间中。另一方面,<cstddef> 是一个 C++ 标头,它将 C 名称包装到 std 命名空间中,这自然是 C++ 方法,因此如果包含 <cstddef> 并且编译器兼容,则必须使用 std::size_t .显然,在 C++ 中,C++ 方法更合适。

从技术上讲,C 标头也可能包含 std 命名空间中的名称。但是 C 标头(以 .h 结尾的那些)也将名称引入全局命名空间(从而污染它)。

【讨论】:

  • 好电话。虽然stddef.h(和其他 17 个 C 头文件)是 C++03 的一部分,但它们会感染全局命名空间,正如您所说,您应该使用 C++ 而不是兼容性函数 - C++ 也提供 malloc 但没有理智的 C++ 程序员会使用它:-)
  • 必须在 std:: 中定义 size_t 并添加 using std::size_t;
  • @Sjoerd:§D.7/2 说:“未指定这些名称是否首先在命名空间 std 的命名空间范围 (3.3.6) 内声明或定义,然后注入显式 using-declarations (7.3.3) 的全局命名空间范围。”
  • current 标准在 D5/2 中声明:“每个 C 标头,每个标头都有一个 name.h 形式的名称,表现得好像每个名称都放在相应 cname 标头的标准库命名空间也被放置在命名空间 std 的命名空间范围内,并且后跟显式 using-declaration"。这可能在 C++0x 中发生了变化(我不知道),但我认为这个答案是正确的。
  • @Philipp:确实如此(不幸的是)。对于当前的标准,查看:open-std.org/jtc1/sc22/open/n2356 可能更准确。这是 1998 年标准的最终草案,但 03 年的变化相对较小。
【解决方案2】:

我更喜欢#include <stddef.h>

C 头文件中的某些名称允许为宏,但设置与 C 规则不同。在 C 中,EXIT_FAILUREisdigit()getc() a.o.是宏。你知道哪些是 C++ 中的宏吗?

其次,只有几个标准的 C 标头需要有 <cfoo> 标头,Posix 标头不需要。您知道哪些标头是标准的,哪些仅由您的编译器提供?

第三,当使用来自第三方 C 库的头文件时,你最终会得到 #include <stddef.h>,我不喜欢混合使用 <stddef.h><cstddef>

第四,新 C++ 标准的当前草案说 <cstdlib> 被允许将符号转储到全局命名空间中(因为显然现在许多编译器已经这样做了),所以使用 #include <cstdlib> 并不能保证全局命名空间将来不会被污染。所以我建议在编写可移植代码时,你应该假设全局命名空间会受到影响(即使现在不允许这样做)。由于似乎只有少数专家知道这一点(请参阅此处 cmets 中的讨论),因此最好使用 <stddef.h>,因为即使是 C++ 初学者也会明白它会污染全局命名空间。

【讨论】:

  • <cstdlib>not “允许将符号转储到 blobal 命名空间中。(§17.4.1.2/4):“然而,在 C++ 标准库中,声明和定义(在 C 中定义为宏的名称除外)在命名空间 std 的命名空间范围 (3.3.5) 内。"
  • @Jerry 在open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#456 上查看(未来)C++0x 的最新版本 引用:“[示例:标头 确实在命名空间 std 中提供了它的声明和定义。它也可以在全局命名空间中提供这些名称。[..]"
  • @Sjoerd:是的,这可能(可能会)最终发生——但目前不允许这样做。
  • 这不是最终会发生的事情,几乎所有编译器都已经这样做了。这就是为什么改变标准,以允许现有的做法!大多数 C++ 编译器都必须使用来自系统 C 编译器的 .h 头文件,不管他们喜欢与否。
  • 您列出的大多数原因听起来像是偏爱 的论据。
【解决方案3】:

<stddef.h> 是 C++ 的正式弃用部分(与 C++ 标准的附件 D 的其余部分一起)。所有这些都是标准 C 的(未弃用)部分,因此即使它们在 C++ 中已弃用,它们几乎肯定会几乎无限期地保持可用。

很多没有被弃用的特性几乎肯定会首先消失——export 已经从当前的 C++0x 草案中消失了,如果我不得不猜测,我'会说异常规范比附件 D 更有可能去。当/如果这些标题确实变得过时,它可能来自 David Vandervoorde 模块提案的成熟版本,它可以轻松呈现 all 标头已过时。

同时,相当多的编译器(尤其是较旧的编译器)并未完全按照标准规定的方式实现 <c*> 标头。如果您想/需要编写与它们一起使用的代码,使用<*.h> 标头而不是<c*> 标头可以获得相当多的好处。

最终,我认为<c*> 标头是寻找问题的解决方案。 C 标准要求这些标头 定义所需的名称——除了保留的名称(例如带有前导下划线后跟另一个下划线或大写字母)之外,根本没有其他名称。保留名称(以及更多名称)在 C++ 中也保留,因此在任何情况下它们都不会与可移植代码中的任何内容发生冲突。因此,所有<c*> 标头都为您提供了在全局命名空间中定义与C 标准库中现有名称冲突的名称的能力。这是一个非常糟糕的想法,甚至不值得考虑这样做,所以从实际的角度来看,你什么也没得到。

编辑:即使这种无用的功能与足够少的真正编译器一起使用,当前的向上梳理 C++0x 草案允许<c*> 标头无论如何都会污染全局命名空间,因此即使理论上的优势也消失了.

【讨论】:

  • 它比你描述的更糟糕:<c*> 标头允许将名称放入全局命名空间,因此 <c*> 标头甚至不让您能够在其中定义名称与 C 标准库中现有名称冲突的全局命名空间。
  • @Sjoerd:请参阅我对您的(不正确的)回复的评论说同样的话。确实很多实现这样做,但当前标准不允许
  • C++0x 的提议措辞允许,见open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#456
【解决方案4】:

两者都在标准中,AFAIK 将继续存在。

形式 cXXX 总是引入 std 命名空间中的名称,形式 XXX.h 总是引入全局命名空间中的名称。两者也可以将名称放在另一个名称空间中(至少在 C++0X 中,以前不是这种情况。鉴于该约束使得不可能从您无法控制的 C 库构建 C++ 库,约束已被删除。g++ 至少在非 glibc 目标上存在这个问题)。

对于传统的 Unix 头文件,在所有实现中,如果您之前定义了所需的功能宏,我已经测试了表单 XXX.h 包含额外的 Unix 标识符。 cXXX 表单的行为在实现之间不一致。所以在实践中我使用 XXX.h 因为我经常需要这些声明。

【讨论】:

  • +1 提到了 实现的不一致,这在历史上对我来说是最令人信服的原因。
  • 我严重怀疑 stddef.h 是否会被禁止,但从技术上讲,这是允许的,因为标准说:“这些 [...] 不保证在未来的修订中成为标准的一部分”。
  • @Philipp,有一些在这样的条款中没有提到的东西被删除了,还有一些东西被保留了......
  • @Philipp:这正是“弃用”一词的定义:)
  • @Armen:正是我引用的内容,参见 §D/2:“……其中 deprecated 被定义为:当前版本标准的规范性,但不是保证在未来的修订中成为标准的一部分。”
【解决方案5】:

<cstddef> 是标准,<stddef.h> 不是。这几乎是结束了。它不会很快被弃用,因为有很多程序依赖它。

【讨论】:

  • c++ 标准中的哪一段确切地说明了这一点?
  • @VJo:我不知道,也不要引用任何标准的段落。但我知道它是。其他人是标准圣经。我会问他们。
  • stddef.h 在当前标准 C++03 中明确提及。请参阅 Armen 的回答,了解您不应使用它们的原因,但它们绝对是 ISO C++ 的一部分。
  • §D.7/1:“为了与 C 标准库和 C Unicode TR 兼容,C++ 标准库提供了 25 个 C 标头,[…]” ;这意味着 <stddef.h> 是 C++ 标准的一部分,但已弃用。
猜你喜欢
  • 2016-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-16
  • 2014-03-12
  • 2013-01-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多