537

我注意到现代 C 和 C++ 代码似乎在几乎所有地方都使用size_t而不是int/ ——从 C 字符串函数的参数到 STL。unsigned int我很好奇这样做的原因及其带来的好处。

4

8 回答 8

421

size_t类型是无符号整数类型,它是sizeof运算符(和offsetof运算符)的结果,因此保证它足够大以包含系统可以处理的最大对象的大小(例如,8Gb 的静态数组)。

size_t类型可能大于、等于或小于,并且您的unsigned int编译器可能会对其进行优化以进行假设。

您可以在 C99 标准第 7.17 节中找到更精确的信息,该标准的草案在 Internet 上以pdf格式提供,或者在 C11 标准第 7.19 节中以pdf 草案的形式提供。

于 2008-09-25T07:08:12.997 回答
105

经典 C(Brian Kernighan 和 Dennis Ritchie 在 The C Programming Language,Prentice-Hall,1978 年描述的 C 的早期方言)没有提供size_t. 引入 C 标准委员会size_t以消除可移植性问题

在 embedded.com 上详细解释(有一个很好的例子)

于 2008-09-25T07:13:02.640 回答
86

简而言之,size_t它永远不会是负数,并且它可以最大限度地提高性能,因为它的 typedef'd 是无符号整数类型,它足够大 - 但不是太大 - 可以表示目标平台上最大可能对象的大小。

大小永远不应该是负数,并且确实size_t是无符号类型。此外,由于size_t是无符号的,您可以存储大约是相应有符号类型的两倍大的数字,因为我们可以使用符号位来表示幅度,就像无符号整数中的所有其他位一样。当我们获得更多位时,我们将可以表示的数字范围乘以大约两倍。

所以,你问,为什么不直接使用unsigned int? 它可能无法容纳足够大的数字。在unsigned int32 位的实现中,它可以表示的最大数字是4294967295. 某些处理器,例如 IP16L32,可以复制大于4294967295字节的对象。

所以,你问,为什么不使用unsigned long int? 它会在某些平台上造成性能损失。标准 C 要求 along至少占用 32 位。IP16L32 平台将每个 32 位长实现为一对 16 位字。这些平台上的几乎所有 32 位运算符都需要两条指令,甚至更多,因为它们使用两个 16 位块中的 32 位。例如,移动一个 32 位的长度通常需要两条机器指令——一条用于移动每个 16 位的块。

使用size_t可以避免这种性能损失。根据这篇精彩的文章,“Typesize_t是一个 typedef,它是一些无符号整数类型的别名,通常是unsigned intor unsigned long,但也可能是unsigned long long。每个标准 C 实现都应该选择足够大的无符号整数——但不大于需要的整数——表示目标平台上最大可能对象的大小。”

于 2010-11-28T03:41:35.613 回答
51

size_t 类型是 sizeof 运算符返回的类型。它是一个无符号整数,能够以字节为单位表示主机支持的任何内存范围的大小。它(通常)与 ptrdiff_t 相关,因为 ptrdiff_t 是有符号整数值,因此 sizeof(ptrdiff_t) 和 sizeof(size_t) 相等。

在编写 C 代码时,无论何时处理内存范围,您都应该始终使用 size_t。

另一方面, int 类型基本上定义为主机可以用来最有效地执行整数运算的(有符号)整数值的大小。例如,在许多较旧的 PC 类型计算机上,值 sizeof(size_t) 将为 4(字节),但 sizeof(int) 将为 2(字节)。16 位算术比 32 位算术更快,尽管 CPU 可以处理高达 4 GiB 的(逻辑)内存空间。

仅当您关心效率时才使用 int 类型,因为它的实际精度很大程度上取决于编译器选项和机器架构。特别是 C 标准指定了以下不变量: sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) 对程序员可用的每个精度的实际表示没有其他限制这些原始类型。

注意:这与 Java 中的不同(它实际上指定了每个类型 'char'、'byte'、'short'、'int' 和 'long' 的位精度)。

于 2008-09-25T07:31:28.103 回答
24

类型 size_t 必须足够大以存储任何可能对象的大小。Unsigned int 不必满足该条件。

例如在 64 位系统中 int 和 unsigned int 可能是 32 位宽,但 size_t 必须足够大以存储大于 4G 的数字

于 2008-09-25T07:08:27.147 回答
4

在研究该主题时,glibc 手册 0.02 的这段摘录也可能是相关的:

2.4 版之前的 GCC 的 size_t 类型和版本存在潜在问题。ANSI C 要求 size_t 始终是无符号类型。为了与现有系统的头文件兼容,GCC 在stddef.h' to be whatever type the system'ssys/types.h' 中定义了 size_t,将其定义为。大多数在 `sys/types.h' 中定义 size_t 的 Unix 系统将其定义为有符号类型。库中的一些代码依赖于 size_t 是一个无符号类型,如果它被签名将无法正常工作。

期望 size_t 为无符号的 GNU C 库代码是正确的。size_t 作为有符号类型的定义是不正确的。我们计划在 2.4 版本中,GCC 将始终将 size_t 定义为无符号类型,而fixincludes' script will massage the system'ssys/types.h' 则不会与此冲突。

同时,我们通过明确告诉 GCC 在编译 GNU C 库时对 size_t 使用无符号类型来解决这个问题。`configure' 将自动检测 GCC 用于 size_t 的类型,并在必要时安排覆盖它。

于 2013-09-24T02:44:37.023 回答
2

如果我的编译器设置为 32 位,size_t那只不过是unsigned int. 如果我的编译器设置为 64 位,size_t那只不过是unsigned long long.

于 2016-01-19T20:55:04.440 回答
-4

size_t 是指针的大小。

所以在 32 位或常见的 ILP32(整数、长整数、指针)模型中 size_t 是 32 位。并且在 64 位或常见的 LP64(长指针)模型中 size_t 是 64 位(整数仍然是 32 位)。

还有其他模型,但这些是 g++ 使用的模型(至少默认情况下)

于 2008-09-27T05:21:29.247 回答