size_t和std::size_t的区别

184
在它们声明的位置、使用时机以及任何其他区别方面,size_tstd::size_t 有何不同之处?

我很想知道C++规范是否将std::size_t链接到C的size_t类型。 - Doug T.
1
请查看类似的问题:链接 - Mankarse
3个回答

115

C的size_t和C++的std::size_t是相同的。

在C中,它在<stddef.h>中定义,在C++中,它在<cstddef>中定义,其内容与C头文件相同(请参见下面引用的语录)。它被定义为sizeof运算符的结果的无符号整数类型

C标准在§17.7/2中说:

size_tsizeof运算符的无符号整数类型

而C++标准(关于cstddef头文件)在§18.1/3中说:

其内容与标准C库头文件相同,但有以下更改

所以,它们两个是相同的;唯一的区别是C++在std命名空间中定义了size_t

请注意上面的那一行还说了"有以下更改",它并不是指size_t,而是指C++向语言中添加的新内容(大多数是C中没有的),这些新内容也在同一个头文件中定义。


维基百科对size_t的范围和存储大小有很好的信息:

size_t的范围和存储大小

size_t实际类型是平台相关的;一个常见的错误是假设size_tunsigned int相同,这可能导致编程错误[3][4],例如从32位到64位架构的转换。

根据1999年的ISO C标准(C99),size_t是一个无符号整数类型。它通常被用作内存分配函数中的参数和返回值类型,以及其他需要表示对象大小的地方。

至少16位的整数类型。

剩余部分可以从维基百科此页面中阅读。

2
这带来了另一个问题,如果STL已经通过C(cstddef)导入了size_t,为什么它还有自己的另一个版本呢? - Alok Save
49
严格来说,如果没有使用using namespace std;using std::size_t;就使用size_t是一个错误。然而,大多数编译器允许这样做,并且标准特别允许它们允许这样做(§D.5/3)。 - Potatoswatter
10
@Potatoswatter:它肯定不能既是错误的又在标准中特别允许吧?如果在标准中,那么它就不是错误的! - Ben Hymers
11
标准规定了标准头文件声明的内容,它们不能声明任何其他未保留的名称。头文件 <cstddef> 可能会声明 ::size_t,因此您不能指望它存在或不存在,除非特别包括 <stddef.h> 或另一个保证声明它的 C 库头文件。 - Potatoswatter
5
我明白你的意思了!我可能被一句话中太多的“允许”字眼搞混了。不过我仍然认为你的第一条评论有些过于强硬;正如你刚才所说,::size_t<stddef.h> 中也存在,所以你并不总是需要用 std:: 来限定它。 - Ben Hymers

19

来自C++03的“17.4.3.1.4 Types”:

对于标准C库中的每种类型T(注169),类型:: T和std :: T保留给实现,当定义时,:: T应与std :: T相同。

注169:

这些类型是clock_t,div_t,FILE,fpos_t,lconv,ldiv_t,mbstate_t,ptrdiff_t,sig_atomic_t,size_t,time_t,tm,va_list,wctrans_t,wctype_t和wint_t。


那么可移植的代码不应该依赖于定义std::T变量吗? - Mankarse
6
如果你只包含对应头文件的C版本,那么不能依赖于它们被定义。如果你包含了<stddef.h>头文件,那么std::size_t可能可用或不可用。如果你包含了<cstddef>头文件,那么std::size_t可用,但size_t可能不可用。 - Dennis Zickefoose
5
相反,C++ 版本的头文件必须在 std:: 中定义它们。该段落说,它也可以在顶级命名空间中定义它们,如果这样做,它必须在 std:: 和顶级命名空间中以相同的方式定义它们。大多数编译器只包含 C 头文件并将名称导入到 std:: 中,因此符号最终会在两个命名空间中都被定义。 - Jan Hudec
4
个人而言,我从不去理会来自C语言的<cxxxxx>头文件或者带有std::前缀的标识符。我仅使用标准C头文件 <xxxxx.h>,这从未成为过问题。因此,在代码中我使用 <stddef.h>size_t,并从未考虑过std::size_t;事实上,我从未想过存在(或可能存在)一个std::size_t - Michael Burr

17

std::size_t实际上是stddef.h中的size_t

cstddef提供如下内容:

#include <stddef.h>
namespace std 
{
  using ::ptrdiff_t;
  using ::size_t;
}

...有效地将之前的定义引入了std命名空间。


正如Nawaz所指出的那样,实际上是相反的。你不能包含<cstddef>并期望得到::size_t,但如果你包含<stddef.h>,你将得到std::size_t - MSalters
4
@MSalters,我不明白。包括<stddef.h>只会得到::size_t - hifier
2
那就是你的实现中存在的一个错误。 - MSalters
4
@MSalters,我有点不明白。难道不应该是相反的吗?<cstddef>来自C++,因此应该定义std::*中的东西吗?另一方面,在C头文件中,比如stddef.h,我只会期望C类型,即::size_t。 - Ela782
14
自C++11以来,这个说法不准确了。如果你包含了<cstddef>头文件,你就可以保证得到std::size_t,并且你可能也会得到::size_t(但不能保证)。如果你包含了<stddef.h>头文件,你就可以保证得到::size_t,并且你可能也会得到std::size_t(但不能保证)。在C++03中是不同的,但那实际上无法实现,并被作为一个缺陷进行了修复。 - Jonathan Wakely
这个答案是完全错误的。这是对实现的假设,其他实现可能不遵循这个假设。标准明确指出cstddef将定义std::size_t,但它可能会或可能不会引入::size_t(既不要求也不禁止)。即使实现引入了::size_t,也可以通过在namespace std中放置using ::size_t;或在全局命名空间中放置using std::size_t;来实现,无法保证实现将使用哪种方法。 - Pharap

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