C语言 size_t与uintptr_t

cwtwac6a  于 2023-06-05  发布在  其他
关注(0)|答案(8)|浏览(235)

C标准保证size_t是一个可以保存任何数组索引的类型。这意味着,从逻辑上讲,size_t应该能够保存任何指针类型。我在谷歌上发现的一些网站上读到,这是法律的的和/或应该总是有效的:

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

因此,在C99中,标准引入了intptr_tuintptr_t类型,它们是保证能够保存指针的有符号和无符号类型:

uintptr_t p = (size_t) v;

那么使用size_tuintptr_t有什么区别?两者都是无符号的,并且都应该能够保存任何指针类型,因此它们在功能上看起来是相同的。除了清晰度之外,是否有任何真实的令人信服的理由使用uintptr_t(或更好的void *)而不是size_t?在一个不透明的结构中,字段将只由内部函数处理,有什么理由不这样做吗?
同样,ptrdiff_t是一个有符号类型,能够保存指针差异,因此能够保存大多数指针,那么它与intptr_t有什么区别呢?
难道所有这些类型不都是为同一功能的不同版本服务的吗?如果不是,原因何在?有什么是我不能用其中一个做而另一个又不能做的?如果是这样的话,为什么C99在语言中添加了两个本质上多余的类型?
我愿意忽略函数指针,因为它们不适用于当前的问题,但请随意提及它们,因为我有一个潜在的怀疑,它们将是“正确”答案的核心。

nmpmafwu

nmpmafwu1#

size_t是一个可以保存任何数组索引的类型。这意味着,从逻辑上讲,size_t应该能够容纳任何指针类型
不一定!让我们回到分段式16位架构的时代,例如:一个数组可能被限制为一个段(所以16位size_t就可以),但是你可以有多个段(所以需要一个32位intptr_t类型来选择段以及其中的偏移量)。我知道这些东西听起来很奇怪,在这些天的统一寻址的非分段架构,但标准必须满足更广泛的品种比“什么是正常的2009年”,你知道!- )

wpcxdonn

wpcxdonn2#

关于你的声明:
C标准保证size_t是一个可以容纳任何数组索引的类型。这意味着,从逻辑上讲,size_t应该能够保存任何指针类型。
很不幸,这是不正确的。指针和数组索引不是一回事。设想一个一致的实现是很合理的,它将数组限制为65536个元素,但允许指针将任何值寻址到一个巨大的128位地址空间中。
C99规定size_t变量的上限由SIZE_MAX定义,并且可以低至65535(参见C99 TR3,7.18.3,在C11中未更改)。在现代系统中,如果指针被限制在这个范围内,它们将受到相当的限制。
在实践中,您可能会发现您的假设成立,但这并不是因为标准保证了这一点。因为它实际上并不能保证。

qlfbtfca

qlfbtfca3#

我将让所有其他的答案代表他们自己关于段限制、奇异架构等的推理。
难道简单的名称差异不足以让我们为正确的事情使用正确的类型吗?
如果存储的是大小,请使用size_t。如果要存储指针,请使用intptr_t。阅读你的代码的人会立即知道“啊哈,这是一个大小的东西,可能是字节”,和“哦,这里有一个指针值被存储为整数,出于某种原因”。
否则,您可以使用unsigned long(或者,在现代,unsigned long long)来处理所有内容。大小并不是一切,类型名具有有用的含义,因为它有助于描述程序。

eaf3rand

eaf3rand4#

最大数组的大小可能小于指针。考虑分段架构-指针可能是32位,但单个段可能只能寻址64 KB(例如旧的实模式8086架构)。
虽然这些在桌面计算机中不再常用,但C标准旨在支持甚至小型的专用架构。例如,仍有正在开发的具有8位或16位CPU的嵌入式系统。

dgenwo3n

dgenwo3n5#

我可以想象(这适用于所有类型名),它可以更好地在代码中传达您的意图。
例如,即使unsigned shortwchar_t在Windows上大小相同(我认为),使用wchar_t而不是unsigned short表明您将使用它来存储宽字符,而不仅仅是一些任意数字。

ig9co6j1

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。)我当然可以想象一个委员会试图覆盖所有基地...

juud5qan

juud5qan7#

size_tuintptr_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 类型。

fcy6dtqo

fcy6dtqo8#

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,反之亦然。

相关问题