我注意到现代 C 和 C++ 代码似乎在几乎每个地方都使用 size_t
,而不是 int
/unsigned int
,从 C 字符串函数的参数到 STL。我很好奇这样做的原因和带来的好处。
经典的 C 语言(由 Brian Kernighan 和 Dennis Ritchie 在《C程序设计语言》(Prentice-Hall,1978)中描述的早期方言)没有提供 size_t
。C 标准委员会引入了 size_t
来消除可移植性问题。
size_t
是永远不会为负数的类型,它最大程度地提高了性能,因为它被typedef为无符号整数类型,足以表示目标平台上最大可能对象的大小,但不会过大。
尺寸永远不应该为负数,而且size_t
是无符号类型。此外,由于size_t
是无符号的,我们可以存储大约两倍于相应有符号类型的数字,因为我们可以使用符号位来表示大小,就像无符号整数中的其他位一样。当我们获得一个额外的比特时,我们将所能表示的数字范围乘以大约二。
那么你会问,为什么不使用unsigned int
?可能无法容纳足够大的数字。在实现中,如果unsigned int
是32位的,则它可以表示的最大数字为4294967295
。一些处理器(例如IP16L32)可以复制大于4294967295
字节的对象。
那么你会问,为什么不使用unsigned long int
?它会对某些平台产生性能损失。标准C要求long
至少占用32位。IP16L32平台将每个32位长作为一对16位字实现。几乎所有的32位运算符在这些平台上都需要两个或更多指令,因为它们使用两个16位块中的32位。例如,移动32位长通常需要两个机器指令——分别移动每个16位块。
使用 size_t
可以避免这种性能损失。根据这篇绝妙的文章,“类型 size_t
是一个 typedef,它是某个无符号整数类型的别名,通常是 unsigned int
或 unsigned long
,但也可能是 unsigned long long
。每个标准的 C 实现都应该选择足够大(但不过大)的无符号整数来表示目标平台上最大可能的对象大小。”
INT_MAX
不能比它更小! - Marc van Leeuwensize_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不同(Java实际上指定了每个类型'char','byte','short','int'和'long'的位精度)。
size_t
是一种无符号整数,能够表示主机支持的任何内存范围的字节数大小。” --> 不对。size_t
能够表示任何单个对象(例如数字、数组、结构体)的大小。整个内存范围可能超过size_t
的表示范围。 - chux - Reinstate Monicasize_t
吗?我希望你不是这个意思。大多数情况下,我们不需要处理地址空间和可移植性等问题的数组。在这些情况下,您可以使用 size_t
。在其他情况下,您可以从(有符号)整数中取出索引。因为无符号整数的未预期下溢行为所导致的混淆比可能在其他情况下出现的可移植性问题更常见且更糟糕。 - johannes_lalalasize_t
。 - 12431234123412341234123index = x - y.. later: if (index < 0) -> fail, otherwise z = arr[index]
.. 如果您在此处使用无符号整数会发生什么。顺便说一下,这也是C++委员会对这个主题的官方立场。 - johannes_lalala类型size_t必须足够大,以便存储任何可能对象的大小。无符号整型不必满足该条件。
例如,在64位系统中,int和unsigned int可能是32位宽度,但size_t必须足够大,以存储大于4G的数字。
size_t
只有在编译器能够接受类型 X 的情况下才需要那么大,使得 sizeof(X) 会产生一个大于 4G 的值。大多数编译器都会拒绝例如 typedef unsigned char foo[1000000000000LL][1000000000000LL]
,即使 foo[65536][65536]
超过了文档中定义的实现限制,也可以合理地被拒绝。 - supercatsize_t
只是一个unsigned int
的typedef。如果我的编译器设置为64位,那么size_t
只是一个unsigned long long
的typedef。请注意,这里的typedef
是一种定义新类型的方式。size_t是指针的大小。
因此,在32位或常见的ILP32(整数、长整型、指针)模型中,size_t为32位。 而在64位或常见的LP64(长整型、指针)模型中,size_t为64位(整数仍为32位)。
还有其他模型,但这些是g++使用的(至少默认情况下)。
size_t
并不一定与指针大小相同,尽管它通常是这样的。指针必须能够指向内存中的任何位置;而size_t
只需足够大以表示最大单个对象的大小。 - Keith Thompsonintptr_t
的大小可能与 void *
指针相同。这不是必需的,但 intptr_t
必须能够容纳所有可能的有效值,以供 void *
指针使用。但是 size_t
没有这个要求。此外,size_t
至少为 16 位,而指针可以更小。 - 12431234123412341234123
size_t
可以表示的确切值范围!如果它不知道,那么谁知道呢?"your compiler might make assumption about it"。 - Marc van Leeuwen