C标准保证size_t
是一个可以保存任何数组索引的类型。这意味着,从逻辑上讲,size_t
应该能够保存任何指针类型。我在谷歌上发现的一些网站上读到,这是法律的的和/或应该总是有效的:
void *v = malloc(10);
size_t s = (size_t) v;
因此,在C99中,标准引入了intptr_t
和uintptr_t
类型,它们是保证能够保存指针的有符号和无符号类型:
uintptr_t p = (size_t) v;
那么使用size_t
和uintptr_t
有什么区别?两者都是无符号的,并且都应该能够保存任何指针类型,因此它们在功能上看起来是相同的。除了清晰度之外,是否有任何真实的令人信服的理由使用uintptr_t
(或更好的void *
)而不是size_t
?在一个不透明的结构中,字段将只由内部函数处理,有什么理由不这样做吗?
同样,ptrdiff_t
是一个有符号类型,能够保存指针差异,因此能够保存大多数指针,那么它与intptr_t
有什么区别呢?
难道所有这些类型不都是为同一功能的不同版本服务的吗?如果不是,原因何在?有什么是我不能用其中一个做而另一个又不能做的?如果是这样的话,为什么C99在语言中添加了两个本质上多余的类型?
我愿意忽略函数指针,因为它们不适用于当前的问题,但请随意提及它们,因为我有一个潜在的怀疑,它们将是“正确”答案的核心。
8条答案
按热度按时间nmpmafwu1#
size_t
是一个可以保存任何数组索引的类型。这意味着,从逻辑上讲,size_t应该能够容纳任何指针类型不一定!让我们回到分段式16位架构的时代,例如:一个数组可能被限制为一个段(所以16位
size_t
就可以),但是你可以有多个段(所以需要一个32位intptr_t
类型来选择段以及其中的偏移量)。我知道这些东西听起来很奇怪,在这些天的统一寻址的非分段架构,但标准必须满足更广泛的品种比“什么是正常的2009年”,你知道!- )wpcxdonn2#
关于你的声明:
C标准保证
size_t
是一个可以容纳任何数组索引的类型。这意味着,从逻辑上讲,size_t
应该能够保存任何指针类型。很不幸,这是不正确的。指针和数组索引不是一回事。设想一个一致的实现是很合理的,它将数组限制为65536个元素,但允许指针将任何值寻址到一个巨大的128位地址空间中。
C99规定
size_t
变量的上限由SIZE_MAX
定义,并且可以低至65535(参见C99 TR3,7.18.3,在C11中未更改)。在现代系统中,如果指针被限制在这个范围内,它们将受到相当的限制。在实践中,您可能会发现您的假设成立,但这并不是因为标准保证了这一点。因为它实际上并不能保证。
qlfbtfca3#
我将让所有其他的答案代表他们自己关于段限制、奇异架构等的推理。
难道简单的名称差异不足以让我们为正确的事情使用正确的类型吗?
如果存储的是大小,请使用
size_t
。如果要存储指针,请使用intptr_t
。阅读你的代码的人会立即知道“啊哈,这是一个大小的东西,可能是字节”,和“哦,这里有一个指针值被存储为整数,出于某种原因”。否则,您可以使用
unsigned long
(或者,在现代,unsigned long long
)来处理所有内容。大小并不是一切,类型名具有有用的含义,因为它有助于描述程序。eaf3rand4#
最大数组的大小可能小于指针。考虑分段架构-指针可能是32位,但单个段可能只能寻址64 KB(例如旧的实模式8086架构)。
虽然这些在桌面计算机中不再常用,但C标准旨在支持甚至小型的专用架构。例如,仍有正在开发的具有8位或16位CPU的嵌入式系统。
dgenwo3n5#
我可以想象(这适用于所有类型名),它可以更好地在代码中传达您的意图。
例如,即使
unsigned short
和wchar_t
在Windows上大小相同(我认为),使用wchar_t
而不是unsigned short
表明您将使用它来存储宽字符,而不仅仅是一些任意数字。ig9co6j16#
回顾过去和未来,并回顾各种古怪的架构分散在景观中,我很确定他们试图 Package 所有现有的系统,并为所有可能的未来系统提供支持。
所以可以肯定的是,事情解决的方式,我们到目前为止还不需要这么多类型。
但即使在LP 64中,一个相当常见的范例,我们也需要size_t和ssize_t作为系统调用接口。我们可以想象一个更受限制的遗留系统或未来系统,其中使用完整的64位类型是昂贵的,他们可能希望在大于4GB的I/O操作上下注,但仍然有64位指针。
我想你一定会想:已经开发出来的,将来可能会出现的。(也许是128位分布式系统互联网范围的指针,但在系统调用中不超过64位,甚至可能是“传统”32位限制。:-)想象一下遗留系统可能会得到新的C编译器...
再看看当时周围的情况。除了无数的286实模式内存模型,CDC 60位字/ 18位指针大型机怎么样?Cray系列怎么样?不用管正常的ILP 64、LP 64、LLP 64。(我一直认为微软对LLP 64自命不凡,应该是P64。)我当然可以想象一个委员会试图覆盖所有基地...
juud5qan7#
size_t
与uintptr_t
除了其他好的答案:
size_t
在<stddef.h>, <stdio.h>, <stdlib.h>, <string.h>, <time.h>, <uchar.h>, <wchar.h>
中定义。它至少是16位。uintptr_t
在<stdint.h>
中定义。* * 可选**。兼容的库可能没有定义它,可能是因为没有足够宽的整数类型来往返void*
-uintptr_t
-void *
。两者都是 unsigned integer 类型。
注意:optional companion
intptr_t
是一个 signed integer 类型。fcy6dtqo8#
这意味着intptr_t必须始终替换size_t,反之亦然。