The C standard guarantees that size_t
is a type that can hold any array index. This means that, logically, size_t
should be able to hold any pointer type. I've read on some sites that I found on the Googles that this is legal and/or should always work:
void *v = malloc(10);
size_t s = (size_t) v;
So then in C99, the standard introduced the intptr_t
and uintptr_t
types, which are signed and unsigned types guaranteed to be able to hold pointers:
uintptr_t p = (size_t) v;
So what is the difference between using size_t
and uintptr_t
? Both are unsigned, and both should be able to hold any pointer type, so they seem functionally identical. Is there any real compelling reason to use uintptr_t
(or better yet, a void *
) rather than a size_t
, other than clarity? In an opaque structure, where the field will be handled only by internal functions, is there any reason not to do this?
By the same token, ptrdiff_t
has been a signed type capable of holding pointer differences, and therefore capable of holding most any pointer, so how is it distinct from intptr_t
?
Aren't all of these types basically serving trivially different versions of the same function? If not, why? What can't I do with one of them that I can't do with another? If so, why did C99 add two essentially superfluous types to the language?
I'm willing to disregard function pointers, as they don't apply to the current problem, but feel free to mention them, as I have a sneaking suspicion they will be central to the "correct" answer.
size_t
是可以容纳任何数组索引类型。 这意味着,从逻辑上讲,为size_t应该可以持有任何指针类型
不必要! 重提例如分割16位架构的天:阵列可能被限制在一个单一的段(因此一个16位size_t
会做),但你可以有多个区段(所以32位intptr_t
将需要类型挑段以及其内的偏移量)。 我知道这些事情在统一寻址非分割结构的这些日子里听起来不可思议,但标准必须满足比“什么在2009年正常”,你知道一个更广泛的 - - !)
关于你的语句:
“C标准保证size_t
是可以容纳任何数组索引类型。这意味着,在逻辑上, size_t
应该能够保持任何指针类型。”
这实际上是一个谬论(不正确的推理产生的误解)(A)。 你可能会认为从前者后者内容,但实际上并不是这样。
指针和数组索引是不一样的东西。 这是相当合理的设想一个一致的实现,限制数组元素65536但允许指针,以解决任何值成块状128位的地址空间。
C99指出一个的上限size_t
变量由定义SIZE_MAX
(参见C99 TR3,7.18.3,不变在C11),这可以是低到65535。 如果他们被限制在这个范围内的现代系统指针将相当有限。
在实践中,你可能会发现你的假设成立,但是这不是因为标准保证了它。 因为它实际上并不能保证它。
(一)这不是某种形式的方式人身攻击,只是说为什么你的陈述是在批判性思维的情况下错误的。 例如,下面的推理也无效:
所有的小狗很可爱。 这个东西很可爱。 所以这事一定是一只小狗。
puppiess的可爱或以其他方式没有关系在这里,所有我指出的是,这两个事实并不导致结论,因为前两句允许对可爱的东西是不是小狗的所有脑干。
这类似于你的第一条语句不一定强制要求第二。
我会让所有其他的答案代表自己关于与部分限制,外来架构,等等的理由。
是不是在名字足够的理由使用正确类型的正确的事情简单的区别 ?
如果你存储大小,使用size_t
。 如果你存储一个指针,使用intptr_t
。 一个人阅读你的代码会立即知道,“啊哈,这是一个大小的东西,可能是在字节”和“哦,这里是被存储为整数的指针值,出于某种原因”。
否则,你可以只使用unsigned long
(或者,在这里这些近代, unsigned long long
)一切。 规模并不代表一切,类型名携带含义,因为它有助于描述程序,它是非常有用的。
这可能是最大的数组的大小是比指针小。 认为分段架构 - 指针可以是32位,但单一的段可以是能够解决仅64KB(例如旧的实模式8086体系结构)。
虽然这些通常不是在台式机上使用了,C标准的目的是支持甚至小,专业化架构。 还有正在与例如8位或16位的CPU开发的嵌入式系统。
我会想像(这也适用于所有类型的名字),它更好地传达你的意图的代码。
例如,即使unsigned short
和wchar_t
是在Windows(我认为)相同的大小,使用wchar_t
而不是unsigned short
表明,你会用它来存储宽字符,而不是只是一些任意数量的意图。
展望都向后和向前,并回顾各种古怪的架构都散落景观,我敢肯定他们试图总结所有的现有系统,并且还提供了一切可能的未来系统。
所以肯定的是,事情的方式解决了,我们至今没有需要这么多种类。
但是,即使在LP64,一个相当普遍的模式,我们需要的size_t和ssize_t供系统调用接口。 可以想见较多受约束的传统的或将来的系统,其中使用完整的64位类型是昂贵的,他们可能要踢上I / O操作大于4GB的,但仍然有64位指针。
我想你不得不怀疑:可能已经发展什么,可能会在未来。 (也许128位分布式系统网络全指针,但在一个系统调用不超过64位,或者甚至是“遗产”的32位的限制。:-)形象地说,原有系统可能会得到新的C编译器.. 。
此外,看看周围的存在,然后。 除了数不胜数的286真实模式记忆模式,如何对疾病预防控制中心的60位字/ 18位指针主机? 如何对克雷系列? 没关系正常ILP64,LP64,LLP64。 (我一直认为微软与pretensious 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,反之亦然。
文章来源: size_t vs. uintptr_t