size_t与uintptr_t

C标准保证size_t是一个可以容纳任何数组索引的types。 这意味着,在逻辑上, size_t应该能够保存任何指针types。 我在Google上发现的一些网站上说,这是合法的和/或应该始终工作:

 void *v = malloc(10); size_t s = (size_t) v; 

那么在C99中,标准引入了intptr_tuintptr_ttypes,它们是有符号和无符号types,保证能够保存指针:

 uintptr_t p = (size_t) v; 

那么使用size_tuintptr_t什么区别呢? 两者都是无符号的,都应该能够容纳任何指针types,所以它们在function上看起来是一样的。 除了清晰度之外,有没有真正有说服力的理由使用uintptr_t (或更好的是void * )而不是size_t ? 在一个不透明的结构中,这个领域只能由内部function来处理,是否有理由不这样做?

同样的道理, ptrdiff_t是一个能够保存指针差异的签名types,因此能够保存大多数指针,所以它与intptr_t有什么不同呢?

并不是所有这些types基本上服务于相同function的普通不同版本? 如果没有,为什么? 我不能用其中一个做我不能用另一个做的事情? 如果是这样的话,为什么C99在语言中增加了两个基本多余的types?

我愿意忽视函数指针,因为它们不适用于当前的问题,但随意提及它们,因为我怀疑它们是“正确”答案的核心。

size_t是一个可以容纳任何数组索引的types。 这意味着,在逻辑上,size_t应该能够保存任何指针types

不必要! 回头看看分段的16位体系结构的时代,例如:一个数组可能被限制在一个单独的段(所以16位size_t会这样做),但是你可能有多个段(所以需要一个32位的intptr_ttypes挑选段以及它内的偏移量)。 我知道在这些统一可寻址的非分段架构中这些东西听起来很奇怪,但标准必须迎合“2009年正常情况”这样的多种types,你知道的!)

关于你的陈述:

“C标准保证了size_t是一个可以容纳任何数组索引的types,这意味着在逻辑上, size_t应该能够保存任何指针types。

这被称为谬误,是由错误推理导致的误解。 你可能会认为后者来自前者,但并不一定如此。

指针和数组索引不是一回事。 设想一个将数组限制为65536个元素的一致性实现是相当合理的,但是允许指针将任何值写入一个大量的128位地址空间。

C99指出, size_tvariables的上限是由SIZE_MAX定义的,并且可以低至65535(参见C99 TR3,7.18.3,在C11中保持不变)。 如果指针在现代系统中被限制在这个范围内,指针将是相当有限的。

在实践中,你可能会发现你的假设是成立的,但这不是因为这个标准能够保证。 因为它实际上不能保证它。

我会让所有其他的答案代表段的限制,异国build筑,等等的理由。

名称的理由不是简单的差异,足以使用正确的types适当的东西?

如果您要存储大小,请使用size_t 。 如果你正在存储一个指针,使用intptr_t 。 读取你的代码的人会立即知道“aha,这是一个大小的东西,可能以字节为单位”,“哦,这是一个指针值存储为整数,出于某种原因”。

否则,你可以使用unsigned long (或者,在这里这些现代, unsigned long long )的一切。 大小不是一切,types名称带有意义,这是有用的,因为它有助于描述程序。

最大数组的大小可能比指针小。 考虑分段体系结构 – 指针可能是32位,但是一个段可能只能处理64KB(例如旧的实模式8086体系结构)。

虽然这些在桌面机器中不常用,但C标准旨在支持甚至是小型的专用体系结构。 例如,仍然有8位或16位CPU开发的embedded式系统。

我会想象(这适用于所有types的名称),它更好地expression了你的代码意图。

例如,即使unsigned shortwchar_t在Windows上的大小相同(我认为),但使用wchar_t而不是unsigned short表示您将使用它来存储一个宽字符,而不是一些任意数字。

回头看看,回想起各种各样的古怪的build筑风格,我很确定他们试图包装所有现有的系统,并提供所有可能的未来系统。

可以肯定的是,事情解决的方式,我们迄今为止不需要太多的types。

但是,即使在LP64这个相当常见的范例中,我们也需要size_t和ssize_t作为系统调用接口。 人们可以想象一个更受限制的遗留系统或将来的系统,其中使用完整的64位types是昂贵的,他们可能想要投入大于4GB的I / O操作,但仍然具有64位指针。

我想你不得不怀疑:可能发展了什么,未来会发生什么。 (也许是128位的分布式系统互联网范围内的指针,但是在系统调用中不超过64位,或者甚至是“遗留的”32位限制。:-)图像遗留系统可能获得新的C编译器。 。

另外,看看那里存在的东西。 除了2800个实模式的内存模块之外,CDC的60位/ 18位指针大型机怎么样? Cray系列怎么样? 不要介意正常的ILP64,LP64,LLP64。 (我一直认为微软有LLP64的优势,应该是P64)。我当然可以想象一个委员会试图覆盖所有的基地。

 int main(){ int a[4]={0,1,5,3}; int a0 = a[0]; int a1 = *(a+1); int a2 = *(2+a); int a3 = 3[a]; return a2; } 

暗示intptr_t必须总是替代size_t,反之亦然。