c++ 我应该为size_t包含哪个头文件?

zbdgwd5y  于 5个月前  发布在  其他
关注(0)|答案(4)|浏览(90)

根据cppreference.comsize_t在几个头中定义,即

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

字符串
从C++11开始,

<cstdlib>
<cwchar>


首先,我想知道为什么会这样,这不是与DRY原则相矛盾吗?
使用size_t时,我应该包含上面哪一个头文件?这有关系吗?

wmvff8tz

wmvff8tz1#

假设我想最小化我正在导入的函数和类型,我会选择cstddef,因为它没有声明任何函数,只声明了6种类型。其他的专注于特定的域(字符串,时间,IO),可能对你无关紧要。
请注意,cstddef只保证定义std::size_t,也就是说,在命名空间std中定义size_t,尽管它也可以在全局命名空间中提供这个名称(实际上,普通的size_t)。
相比之下,stddef.h(也是C中可用的头文件)保证在全局命名空间中定义size_t,并且 may 还提供std::size_t

i7uaboj4

i7uaboj42#

事实上,几个头文件的概要(包括在C++标准中)专门包括size_t以及进一步的头文件定义了size_t类型(基于C标准,因为<cX>头文件只是ISO C <X.h>头文件,并注意到没有删除size_t的变化)。

C++标准然而,引用<cstddef>来定义std::size_t

  • 在 *18.2类型 * 中,
  • 在 *5.3.3尺寸 * 中,
  • 在 *3.7.4.2解除分配功能 *(参见18.2)中,
  • 在 *3.7.4.1分配功能 *(也参考18.2)中。

因此,由于<cstddef>只引入了类型而没有函数,我坚持使用这个头文件来使std::size_t可用。

注意几点:

1.std::size_t的类型可以使用decltype获得,不包括header
如果您打算在代码中引入typedef,(例如,因为您编写了一个容器并希望提供size_type typedef),您可以使用全局sizeofsizeof...alignof运算符来定义类型,而不包括任何头,因为这些运算符根据标准定义返回std::size_t,您可以使用decltype关于他们:

using size_type = decltype(alignof(char));

字符串
1.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_tstdstd::size_t
引用stdstd::size_t是格式错误的,除非通过包含适当的报头来声明名称。
1.用户不能重新定义std::size_t,尽管可能有多个typedef引用同一命名空间中的同一类型。
虽然std中出现size_t的多个定义是完全有效的,但根据 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不是模板专门化)。Extending the namespace std *
vwkv1x7d

vwkv1x7d3#

所有的标准库头文件都有相同的定义;你在自己的代码中包含哪一个并不重要。在我的计算机上,我在_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

字符串

s4n0splo

s4n0splo4#

你可以不使用header:

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

字符串
这是因为C++标准要求:
sizeofsizeof...的结果是一个std::size_t类型的常量。[注:std::size_t在标准头文件<cstddef>(18.2)中定义。- end note ]
换言之,该标准要求:

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


还要注意的是,在全局和std命名空间中声明这个typedef是完全可以的,只要它匹配相同 typedef-name 的所有其他typedef声明(不匹配的声明会发出编译器错误)。
这是因为:

  • §7.1.3.1 typedef-name 不像类声明(9.1)或枚举声明那样引入新类型。
  • §7.1.3.3在一个给定的非类作用域中,typedef说明符可以用来重新定义在该作用域中声明的任何类型的名称,以引用它已经引用的类型。

对于怀疑者说这构成了在命名空间std中添加新类型,并且这种行为被标准明确禁止,这就是UB,仅此而已;我不得不说,这种态度相当于忽视和否认对潜在问题的更深入理解。
标准禁止在命名空间std中添加新的声明和定义,因为这样做可能会把标准库弄得一团糟,并把自己的腿踢断。对于标准编写者来说,让用户专门化一些特定的事情并禁止做任何其他事情是更容易的,而不是禁止用户不应该做的每一件事,(和那条腿)。他们在过去要求没有标准容器应该用不完整的类型示例化时就是这样做的,而事实上,一些容器可以很好地做到这一点(参见The Standard Librarian: Containers of Incomplete Types by Matthew H. Austern):
.最后,这一切似乎太模糊,太不理解;标准化委员会认为没有任何选择,除了说STL容器不应该与不完整的类型一起工作。为了更好地衡量,我们也将这一禁令应用于标准库的其余部分。
.现在回想起来,现在对这项技术有了更好的理解,这个决定似乎基本上仍然是正确的。是的,在某些情况下,可以实现一些标准容器,以便它们可以用不完整的类型示例化-但很明显,在其他情况下,这将是困难的或不可能的。我们尝试的第一个测试,使用std::vector,恰好是个容易的案子
考虑到语言规则要求std::size_t完全是decltype(sizeof(int)),执行namespace std { using size_t = decltype(sizeof(int)); }是不会破坏任何东西的事情之一。
在C11之前,没有decltype,因此没有办法在一个简单的语句中声明sizeof结果的类型,而不涉及大量的模板。size_t在不同的目标体系结构上别名不同的类型,但是,仅仅为sizeof的结果添加一个新的内置类型并不是一个优雅的解决方案,并且没有标准的内置typedef。因此,当时最可移植的解决方案是将size_t类型别名放在某些特定的头部和文档中,
在C
11中,现在有一种方法可以将标准的确切要求写为一个简单的声明。

相关问题