简体   繁体   English

我应该为 `size_t` 包含哪个标题?

[英]Which header should I include for `size_t`?

According to cppreference.com size_t is defined in several headers, namely根据cppreference.com size_t定义在几个头文件中,即

<cstddef>
<cstdio>
<cstring>
<ctime>

And, since C++11, also in而且,从 C++11 开始,也在

<cstdlib>
<cwchar> 

First of all, I wonder why this is the case.首先,我想知道为什么会这样。 Isn't this in contradiction to the DRY principle?这不是与DRY原则相矛盾吗?

Which one of the above headers should I include to use size_t ?要使用size_t我应该包含上述哪一个标头? Does it matter at all?这有关系吗?

Assuming I wanted to minimize the functions and types I was importing I'd go with cstddef as it doesn't declare any functions and only declares 6 types.假设我想最小化我正在导入的函数和类型,我会使用cstddef因为它不声明任何函数而只声明 6 种类型。 The others focus on particular domains (strings, time, IO) that may not matter to you.其他人专注于可能对您无关紧要的特定领域(字符串、时间、IO)。

Note that cstddef only guarantees to define std::size_t , that is, defining size_t in namespace std , although it may provide this name also in the global namespace (effectively, plain size_t ).请注意, cstddef仅保证定义std::size_t ,即在命名空间std定义size_t ,尽管它可以在全局命名空间中提供此名称(实际上是普通的size_t )。

In contrast, stddef.h (which is also a header available in C) guarantees to define size_t in the global namespace, and may also provide std::size_t .相比之下, stddef.h (也是 C 中可用的头文件)保证在全局命名空间中定义size_t ,并且还可能提供std::size_t

In fact the synopsis (included in the C++ standard) of several headers specifially include size_t as well as further headers define the type size_t (based on the C standard as the <cX> headers are just ISO C <Xh> headers with noted changes where removal of size_t is not indicated).事实上,几个头文件的概要(包含在 C++ 标准中)特别包括size_t以及进一步的头文件定义了size_t类型(基于 C 标准,因为<cX>头文件只是 ISO C <Xh>头文件,其中有明显的变化)未指示删除size_t )。

The C++ standard however, refers to <cstddef> for the definition of std::size_t然而, C++ 标准引用<cstddef>来定义std::size_t

  • in 18.2 Types ,18.2 类型中
  • in 5.3.3 Sizeof ,5.3.3 Sizeof 中
  • in 3.7.4.2 Deallocation functions (which refers to 18.2) and3.7.4.2 解除分配函数(指 18.2)和
  • in 3.7.4.1 Allocation functions (also refers to 18.2).3.7.4.1 分配函数中(也参考 18.2)。

Therefore and because of the fact that <cstddef> only introduces types and no functions, I'd stick to this header to make std::size_t available.因此,由于<cstddef>仅引入类型而没有引入函数这一事实,我会坚持使用此标头以使std::size_t可用。


Note a few things :请注意以下几点:

  1. The type of std::size_t is obtainable using decltype without including a header可以使用decltype获得std::size_t的类型而不包括头

    If you're planning to introduce a typedef in your code anyway (ie because you write a container and want to provide a size_type typedef) you can use the global sizeof , sizeof... or alignof operators to define your type without including any headers at all since theose operators return std::size_t per standard definition and you can use decltype on them:如果您打算在代码中引入 typedef(即因为您编写了一个容器并希望提供一个size_type typedef),您可以使用全局sizeofsizeof...alignof运算符来定义您的类型,而无需包含任何标题因为这些运算符根据标准定义返回std::size_t并且您可以对它们使用decltype

     using size_type = decltype(alignof(char));
  2. std::size_t is not per se globally visible although functions with std::size_t arguments are. std::size_t本身并不全局可见,虽然与功能std::size_t论点。

    The implicitly declared global allocation and deallocation functions隐式声明的全局分配和释放函数

    void* operator new(std::size_t); void* operator new[](std::size_t); void operator delete(void*); void operator delete[](void*);

    do NOT introduce size_t , std or std::size_t and不要引入size_tstdstd::size_t

    referring to std or std::size_t is ill-formed unless the name has been declared by including the appropriate header.引用stdstd::size_t是格式错误的,除非通过包含适当的头文件来声明名称。

  3. The user may not redefine std::size_t although it is possible to have multiple typedefs referring to the same type in the same namespace.用户不能重新定义std::size_t尽管可能有多个 typedef 引用同一命名空间中的同一类型。

    Although, the occurrence of multiple definitions of size_t within std is perfectly valid as per 7.1.3 / 3 , it is not allowed to add any declarations to namespace std as per 17.6.4.2.1 / 1 :尽管根据7.1.3 / 3std出现多个size_t定义是完全有效的,但不允许根据17.6.4.2.1 / 1namespace std添加任何声明:

    The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified.如果 C++ 程序向命名空间 std 或命名空间 std 内的命名空间添加声明或定义,则它的行为是未定义的,除非另有说明。

    Adding a proper typedef for size_t to the namespace does not violate 7.1.3 but it does violate 17.6.4.2.1 and leads to undefined behaviour.size_t的适当 typedef 添加到命名空间不会违反7.1.3,但确实违反17.6.4.2.1并导致未定义的行为。

    Clarification: Try not to misinterpret 7.1.3 and do not add declarations or definitions to std (except a few template specialization cases where a typedef is not a template specialization).澄清:尽量不要误解7.1.3并且不要向std添加声明或定义(除了一些 typedef 不是模板特化的模板特化情况)。 Extending the namespace std 扩展namespace std

All standard library header files have the same definition;所有标准库头文件都有相同的定义; it does not matter which one you include in your own code.您在自己的代码中包含哪一个并不重要。 On my computer, I have the following declaration in _stddef.h .在我的计算机上,我在_stddef.h有以下声明。 This file is included by every file you listed.您列出的每个文件都包含此文件。

/*
   Define the size_t type in the std namespace if in C++ or globally if in C.
   If we're in C++, make the _SIZE_T macro expand to std::size_t
*/

#if !defined(_SIZE_T) && !defined(_SIZE_T_DEFINED)
#  define _SIZE_T_DEFINED
#if defined(_WIN64)
   typedef unsigned __int64 size_t;
#else
   typedef unsigned int size_t;
#endif
#  if defined(__cplusplus)
#    define _SIZE_T std::size_t
#  else
#    define _SIZE_T size_t
#  endif
#endif

You could do without a header:你可以没有标题:

using size_t = decltype(sizeof(int));
using size_t = decltype(sizeof 1); //  The shortest is my favourite.
using size_t = decltype(sizeof "anything");

This is because the C++ standard requires:这是因为 C++ 标准要求:

The result of sizeof and sizeof... is a constant of type std::size_t . sizeofsizeof...的结果是std::size_t类型的常量。 [ Note: std::size_t is defined in the standard header <cstddef> (18.2). [ 注意: std::size_t在标准头文件<cstddef> (18.2) 中定义。 — end note ] — 尾注 ]

In other words, the standard requires:换言之,该标准要求:

static_assert(std::is_same<decltype(sizeof(int)), std::size_t>::value,
              "This never fails.");

Also note, that it is perfectly fine to make this typedef declaration in the global and in std namespace, as long as it matches all other typedef declarations of the same typedef-name (a compiler error is issued on non-matching declarations).另请注意,在全局和std命名空间中进行此typedef声明是完全没问题的,只要它与相同typedef 名称的所有其他typedef声明匹配(在不匹配的声明上会发出编译器错误)。

This is because:这是因为:

  • §7.1.3.1 A typedef-name does not introduce a new type the way a class declaration (9.1) or enum declaration does. §7.1.3.1 typedef-name不会像类声明 (9.1) 或枚举声明那样引入新类型。

  • §7.1.3.3 In a given non-class scope, a typedef specifier can be used to redefine the name of any type declared in that scope to refer to the type to which it already refers. §7.1.3.3 在给定的非类作用域中,可以使用typedef说明符重新定义在该作用域中声明的任何类型的名称,以引用它已经引用的类型。


To sceptics saying that this constitutes an addition of a new type into namespace std , and such an act is explicitly prohibited by the standard, and this is UB and that is all there to it;怀疑论者说这构成了在命名空间std添加新类型,并且标准明确禁止这种行为,这就是 UB ,这就是全部; I have to say that this attitude amounts to ignoring and denying deeper understanding of the underlying issues.我不得不说,这种态度等于忽视和否认对潜在问题的更深入理解。

The standard bans adding new declarations and definitions into namespace std because by doing so the user may make a mess of the standard library and shoot his entire leg off.该标准禁止在命名空间std添加新的声明和定义,因为这样做用户可能会把标准库弄得一团糟,并把他的整条腿都打掉。 For the standard writers it was easier to let the user specialize a few specific things and ban doing anything else for good measure, rather than ban every single thing which the user should not do and risk missing something important (and that leg).对于标准编写者来说,让用户专注于一些特定的事情并禁止做任何其他事情来更好地衡量更容易,而不是禁止用户不应该做的每一件事,并冒着遗漏重要的事情(和那条腿)的风险。 They did it in the past when requiring that no standard container shall be instantiated with an incomplete type, while in fact some containers could well do (see The Standard Librarian: Containers of Incomplete Types by Matthew H. Austern ):过去,当要求不使用不完整类型实例化任何标准容器时,他们这样做了,而实际上一些容器完全可以做到(参见Matthew H. Austern 的标准图书馆员:不完整类型的容器):

... In the end, it all seemed too murky and too poorly understood; ......最后,这一切似乎太模糊,太难理解了; the standardization committee didn't think there was any choice except to say that STL containers aren't supposed to work with incomplete types.标准化委员会认为除了说 STL 容器不应该与不完整的类型一起工作之外,别无选择。 For good measure, we applied that prohibition to the rest of the standard library too.为了更好地衡量,我们也将该禁令应用于标准库的其余部分。

... In retrospect, now that the technology is better understood, that decision still seems basically right. ... 回想起来,现在对技术有了更好的理解,这个决定似乎仍然基本正确。 Yes, in some cases it's possible to implement some of the standard containers so that they can be instantiated with incomplete types — but it's also clear that in other cases it would be difficult or impossible.是的,在某些情况下,可以实现一些标准容器,以便用不完整的类型实例化它们——但很明显,在其他情况下,这将是困难的或不可能的。 It was mostly chance that the first test we tried, using std::vector , happened to be one of the easy cases.我们使用std::vector尝试的第一个测试碰巧是一个简单的案例,这主要是偶然的。

Given that the language rules require std::size_t to be exactly decltype(sizeof(int)) , doing namespace std { using size_t = decltype(sizeof(int)); }鉴于语言规则要求std::size_t完全是decltype(sizeof(int))namespace std { using size_t = decltype(sizeof(int)); }namespace std { using size_t = decltype(sizeof(int)); } namespace std { using size_t = decltype(sizeof(int)); } is one of those things that do not break anything. namespace std { using size_t = decltype(sizeof(int)); }是不破坏任何东西的事情之一。

Prior to C++11 there was no decltype and thus no way to declare the type of sizeof result in one simple statement without getting a good deal of templates involved.在 C++11 之前,没有decltype ,因此无法在不涉及大量模板的情况下在一个简单的语句中声明sizeof结果的类型。 size_t aliases different types on different target architectures, however, it would not be an elegant solution to add a new built-in type just for the result of sizeof , and there are no standard built-in typedefs. size_t在不同的目标架构上为不同的类型设置别名,但是,仅仅为sizeof的结果添加新的内置类型并不是一个优雅的解决方案,并且没有标准的内置 typedef。 Hence, the most portable solution at the time was to put size_t type alias in some specific header and document that.因此,当时最便携的解决方案是将size_t类型别名放在某些特定的标题和文档中。

In C++11 there is now a way to write down that exact requirement of the standard as one simple declaration.在 C++11 中,现在有一种方法可以将标准的确切要求写成一个简单的声明。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM