我该包含stddef.h还是cstddef来使用size_t?

30

在C++中,当我想使用size_t时,我应该包含<stddef.h>还是<cstddef>?我听说过有些人说<cstddef>不好,应该废弃它。为什么会这样呢?


1
请查看我的更新答案,链接在这里。https://dev59.com/EmYr5IYBdhLWcg3wLnVA#43016708 - Santiago Varela
5个回答

45

stddef.h 是C语言的头文件。其中 size_t 名称在全局命名空间中。而另一方面,<cstddef> 是一个C++头文件,它将C名称包装进 std 命名空间中,这是自然的C++做法,因此如果您包含了 <cstddef> 并且编译器符合标准,您将需要使用 std::size_t。显然,在C++中,C++的方法更为适当。

从技术上讲,C头文件也可能包含 std 命名空间中的名称。但是以 .h 结尾的C头文件还将名称引入全局命名空间(因此污染了它)。


4
好的,你说得对。尽管stddef.h(以及其他17个C头文件)是C++03的一部分,但它们会感染全局命名空间。正如你所说,应该使用C++, 而不是兼容性函数。C++也提供了malloc,但没有一个理智的C++程序员会使用它 :-) - paxdiablo
1
<stddef.h> 必须在 std:: 中定义 size_t,并添加 using std::size_t; - Sjoerd
3
@Sjoerd: §D.7/2 中写道:“这些名称是否在命名空间std的命名空间作用域(3.3.6)中首先被声明或定义并通过显式的using-declarations (7.3.3) 注入到全局命名空间作用域中,是未指定的。” - Philipp
1
@pax:这意味着G++违反了当前的标准,对吗?也许这就是它被更改的原因。 - Philipp
2
@Philipp:这是真的(不幸的是)。对于当前标准,最准确的可能是查看:http://www.open-std.org/jtc1/sc22/open/n2356/。那是1998年标准的最终草案,但'03年的更改相对较小。 - Jerry Coffin
显示剩余16条评论

16

我更喜欢使用#include <stddef.h>

C头文件中的一些名称允许是宏,但其集合与C规则不同。在C中,EXIT_FAILUREisdigit()getc()等都是宏。您知道哪些是C++中的宏吗?

其次,只有少数标准C头文件需要具有<cfoo>头文件,Posix头文件不包括在内。您知道哪些头文件是标准的,哪些是由编译器提供的吗?

第三,当使用第三方C库的头文件时,您将得到#include <stddef.h>,我更喜欢不混用<stddef.h><cstddef>

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


5
<cstdlib> 不允许将符号倾泻到全局命名空间中(§17.4.1.2/4):"然而,在 C++ 标准库中,除了在 C 中定义为宏的名称之外,声明和定义都在命名空间 std 的命名空间作用域内(3.3.5)。" - Jerry Coffin
@Jerry,请前往 http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#456 查看最新版本的(未来)C++0x。引用:“[示例:头文件 <cstdlib> 确保在命名空间 std 中提供其声明和定义。它也可能在全局命名空间中提供这些名称。[..]” - Sjoerd
1
@Sjoerd:是的,那可能(很可能)最终会发生--但目前还不允许。 - Jerry Coffin
5
这并不是最终会发生的事情,这几乎是所有编译器已经在做的事情。这就是为什么标准被改变,以允许现有的做法!大多数C++编译器将不得不使用系统C编译器中的.h头文件,无论他们喜欢与否。 - Bo Persson
@ Bo 又编辑了一次文本。也许在所有的错误修复之后我应该重构我的文本?! :P - Sjoerd
6
你列举的大多数理由听起来都是偏向使用<cstddef>的论点。 - Adrian McCarthy

12

<stddef.h> 是C++的一个被官方弃用的部分(与C++标准的附录D一起),但所有这些都是标准C的非弃用部分。因此,尽管它们在C++中被弃用,它们几乎肯定会一直保持可用。

许多未被弃用的功能很可能首先消失——export已经从当前的C++0x草案中消失了,如果我不得不猜测,我会说异常规范比附录D更有可能被删除。当/如果这些头文件真正过时时,它们可能来自David Vandervoorde成熟的模块提议的版本,该提议可以轻松地使所有头文件过时。

同时,相当数量的编译器(特别是旧版)没有按照标准规定精确实现<c*>头文件。如果你想/需要编写能够与它们一起使用的代码,使用<*.h>头文件而不是<c*>头文件可以让你获得相当大的收益。

最終,我认为<c*>头文件只是一种寻找问题的解决方案。C标准要求这些头文件定义必需的名称--除了保留的名称(如前导下划线后面跟着另一个下划线或大写字母的名称)外,没有其他名称。这些保留名称(和更多名称)在C++中也是保留的,因此它们无论如何都不会与可移植代码中的任何内容冲突。因此,所有<c*>头文件给你的就只是能够在全局命名空间中定义一个与C标准库中现有名称冲突的名称的能力。这种想法是如此的糟糕,甚至不值得考虑,因此从实际的角度来看,你没有获得任何东西。

编辑:即使那个无用的功能在现实编译器中工作得足够好,当前正在开发中的C++0x的草案也允许<c*>头文件污染全局命名空间,因此即使是理论上的优势也已经不存在了。


这比你描述的还要糟糕:<c*>头文件允许将名称放入全局命名空间中,因此<c*>头文件甚至不能让你在全局命名空间中定义一个与C标准库中现有名称冲突的名称。 - Sjoerd
@Sjoerd:请看一下我对你(错误的)回复的评论。许多实现确实这样做,但是根据当前标准,这是不允许的。 - Jerry Coffin
C++0x的拟议措辞允许这样做,参见http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#456。 - Sjoerd

2

这两种形式都是标准的,据我所知,它们会一直存在。

cXXX形式总是引入std命名空间中的名称,而XXX.h形式总是引入全局命名空间中的名称。两者也可以将名称放在另一个命名空间中(至少在C++0X中是这样的,在此之前不是这样的。由于遵守该约束使得从不受控制的C库构建C++库成为不可能,因此移除了该约束。g ++至少在非glibc目标上存在该问题)。

对于传统的Unix头文件,在我测试过的所有实现中,如果您在使用XXX.h之前定义了所需的特征宏,则该形式会包含其他Unix标识符。cXXX形式的行为在实现之间不一致。因此,实际上我使用XXX.h,因为我经常需要这些声明。


我严重怀疑 stddef.h 会被禁止,但从技术上讲,它是允许的,因为标准规定:“这些内容未来的修订版本中不保证成为标准的一部分”。 - Philipp
2
@Philipp,有一些在这样的条款中没有提到被删除的事情,还有一些正在保留... - AProgrammer
@Armen:正是我引用的那个,参见 §D/2:“…其中deprecated的定义为:规范适用于当前版本的标准,但不保证在未来修订中成为标准的一部分。” - Philipp
@Philipp:问题在于这与标准的任何其他部分没有区别——即使它没有被弃用(例如export),也不能保证将来的标准版本中会包含它。 - Jerry Coffin
@Jerry:我同意,“deprecated”的使用相当模糊。我认为export可以被移除,因为大多数主要编译器没有实现它。“Deprecated”似乎更像是一个愿望而不是一个定义。另一方面,我并不认为包含C头文件实际上更可取——至少这是不一致的。 - Philipp
显示剩余2条评论

-3

<cstddef> 是标准的,而 <stddef.h> 则不是。这就是事实。它不会很快被弃用,因为有很多程序依赖于它。


4
C++标准中确切说明这一点的段落是哪个? - BЈовић
@VJo:我不知道,也不要引用任何标准的段落。但我知道它是标准的。其他人是标准圣经。我会问他们。 - Puppy
3
“stddef.h”在当前C++03标准中被明确提及。阅读Armen的回答可了解为什么不应使用它们,但它们绝对是ISO C++的一部分。 - paxdiablo
1
§D.7/1:“为了与C标准库和C Unicode TR兼容,C++标准库提供了25个C头文件,[…]”;这意味着<stddef.h>是C++标准的一部分,但已被弃用。 - Philipp

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