C++ 我应该为“size_t”包含哪个标题?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36594569/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Which header should I include for `size_t`?
提问by idclev 463035818
According to cppreference.comsize_t
is defined in several headers, namely
根据cppreference.comsize_t
定义在几个headers中,即
<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 DRYprinciple? However, my question is:
首先我想知道为什么会这样。这不是与DRY原则相矛盾吗?但是,我的问题是:
Which one of the above headers should I include to use size_t
? Does it matter at all?
我应该使用上述哪一个标题size_t
?这有关系吗?
采纳答案by Sean
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. The others focus on particular domains (strings, time, IO) that may not matter to you.
假设我想最小化我正在导入的函数和类型,我会使用cstddef
它,因为它不声明任何函数而只声明 6 种类型。其他人专注于可能对您无关紧要的特定领域(字符串、时间、IO)。
Note that cstddef
only guarantees to define std::size_t
, that is, defining size_t
in namespace std
, although it mayprovide this name also in the global namespace (effectively, plain size_t
).
请注意,cstddef
仅保证定义std::size_t
,即size_t
在命名空间中定义std
,尽管它也可以在全局命名空间中提供此名称(实际上是普通的size_t
)。
In contrast, stddef.h
(which is also a header available in C) guarantees to define size_t
in the global namespace, and mayalso provide std::size_t
.
相比之下,stddef.h
(这也是 C 中可用的头文件)保证size_t
在全局命名空间中定义,并且还可能提供std::size_t
.
回答by Pixelchemist
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 <X.h>
headers with noted changes where removal of size_t
is not indicated).
事实上,几个头文件的概要(包含在 C++ 标准中)特别包括size_t
以及进一步的头文件定义了类型size_t
(基于 C 标准,因为<cX>
头文件只是 ISO C<X.h>
头文件,其中size_t
没有指出删除的注意事项)。
The C++ standardhowever, refers to <cstddef>
for the definition of std::size_t
然而,C++ 标准是指<cstddef>
用于定义std::size_t
- in 18.2 Types,
- in 5.3.3 Sizeof,
- in 3.7.4.2 Deallocation functions(which refers to 18.2) and
- in 3.7.4.1 Allocation functions(also refers to 18.2).
- 在18.2 类型中,
- 在5.3.3 Sizeof 中,
- 在3.7.4.2 解除分配函数(指 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 :
请注意以下几点:
The type of
std::size_t
is obtainable usingdecltype
without including a headerIf you're planning to introduce a typedef in your code anyway (i.e. because you write a container and want to provide a
size_type
typedef) you can use the globalsizeof
,sizeof...
oralignof
operators to define your type without including any headers at all since theose operators returnstd::size_t
per standard definition and you can usedecltype
on them:using size_type = decltype(alignof(char));
std::size_t
is not per se globally visible although functions withstd::size_t
arguments are.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
orstd::size_t
andreferring to
std
orstd::size_t
is ill-formed unless the name has been declared by including the appropriate header.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.Although, the occurrence of multiple definitions of
size_t
withinstd
is perfectly valid as per 7.1.3 / 3, it is not allowed to add any declarations tonamespace std
as per 17.6.4.2.1 / 1: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.
Adding a proper typedef for
size_t
to the namespace does not violate 7.1.3but it does violate 17.6.4.2.1and leads to undefined behaviour.Clarification: Try not to misinterpret 7.1.3and do not add declarations or definitions to
std
(except a few template specialization cases where a typedef is not a template specialization). Extending thenamespace std
std::size_t
可以使用decltype
不包含标题的类型获取如果您打算在代码中引入 typedef(即因为您编写了一个容器并希望提供一个
size_type
typedef),您可以使用 globalsizeof
,sizeof...
oralignof
运算符来定义您的类型,而根本不包含任何标题,因为这些运算符返回std::size_t
per标准定义,您可以decltype
对它们使用:using size_type = decltype(alignof(char));
std::size_t
尽管带有std::size_t
参数的函数是全局可见的,但它本身并不是全局可见的。隐式声明的全局分配和释放函数
void* operator new(std::size_t); void* operator new[](std::size_t); void operator delete(void*); void operator delete[](void*);
不要介绍
size_t
,std
或std::size_t
和引用
std
或std::size_t
格式错误,除非已通过包含适当的标头来声明名称。std::size_t
尽管可能有多个 typedef 引用同一命名空间中的同一类型,但用户可能无法重新定义。虽然,的多个定义的发生
size_t
内std
是按照完全有效7.1.3 / 3,它是不允许的任何声明添加到namespace std
每如17.6.4.2.1 / 1:如果 C++ 程序向命名空间 std 或命名空间 std 内的命名空间添加声明或定义,则它的行为是未定义的,除非另有说明。
为
size_t
命名空间添加适当的 typedef不会违反7.1.3,但确实违反17.6.4.2.1并导致未定义的行为。澄清:尽量不要误解7.1.3并且不要向其中添加声明或定义
std
(除了一些 typedef 不是模板特化的模板特化情况)。扩展namespace std
回答by vll
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
. This file is included by every file you listed.
所有标准库头文件都有相同的定义;您在自己的代码中包含哪一个并不重要。在我的计算机上,我在_stddef.h
. 您列出的每个文件都包含此文件。
/*
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
回答by Maxim Egorushkin
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
andsizeof...
is a constant of typestd::size_t
. [ Note:std::size_t
is defined in the standard header<cstddef>
(18.2). — end note ]
sizeof
and的结果sizeof...
是一个类型为 的常量std::size_t
。[ 注意:std::size_t
在标准头文件<cstddef>
(18.2) 中定义。— 尾注 ]
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).
另请注意,typedef
在全局和std
命名空间中进行此声明是完全没问题的,只要它与typedef
具有相同typedef-name 的所有其他声明相匹配(在不匹配的声明中会发出编译器错误)。
This is because:
这是因为:
§7.1.3.1 A typedef-namedoes not introduce a new type the way a class declaration (9.1) or enum declaration does.
§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.1 typedef-name不会像类声明 (9.1) 或枚举声明那样引入新类型。
§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; I have to say that this attitude amounts to ignoring and denying deeper understanding of the underlying issues.
怀疑论者说,这构成了向 namespace 中添加新类型std
,并且标准明确禁止这种行为,这就是 UB ,仅此而已;我不得不说,这种态度等于忽视和否认对潜在问题的更深入理解。
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. 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):
该标准禁止在命名空间中添加新的声明和定义,std
因为这样做可能会将标准库弄得一团糟,并把他的整条腿都打掉。对于标准编写者来说,让用户专注于一些特定的事情并禁止做任何其他事情来更好地衡量更容易,而不是禁止用户不应该做的每一件事,并冒着遗漏重要的事情(和那条腿)的风险。过去,当要求不使用不完整类型实例化任何标准容器时,他们这样做了,而实际上一些容器完全可以做到(参见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. 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.
......最后,这一切似乎太模糊,太难理解了;标准化委员会认为除了说 STL 容器不应该与不完整的类型一起工作之外,别无选择。为了更好地衡量,我们也将该禁令应用于标准库的其余部分。
... 回想起来,现在对技术有了更好的理解,这个决定似乎仍然基本正确。是的,在某些情况下,可以实现一些标准容器,以便用不完整的类型实例化它们——但很明显,在其他情况下,这将是困难的或不可能的。我们尝试的第一个测试,使用
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)); }
is one of those things that do not break anything.
鉴于语言规则要求std::size_t
完全一致decltype(sizeof(int))
,做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. 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. Hence, the most portable solution at the time was to put size_t
type alias in some specific header and document that.
在 C++11 之前,没有decltype
也没有办法sizeof
在不涉及大量模板的情况下在一个简单的语句中声明结果的类型。size_t
在不同的目标架构上为不同的类型设置别名,但是,仅仅为 的结果添加新的内置类型并不是一个优雅的解决方案sizeof
,并且没有标准的内置 typedef。因此,当时最便携的解决方案是将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 中,现在有一种方法可以将标准的确切要求写成一个简单的声明。