size_t vs. uintptr_t

Chr*_*utz 245 c pointers size-t

C标准保证这size_t是一种可以保存任何数组索引的类型.这意味着,逻辑上,size_t应该能够保存任何指针类型.我在Googles上发现的一些网站上看到这是合法的和/或应该始终有效:

void *v = malloc(10);
size_t s = (size_t) v;
Run Code Online (Sandbox Code Playgroud)

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

uintptr_t p = (size_t) v;
Run Code Online (Sandbox Code Playgroud)

那么使用size_t和有uintptr_t什么区别?两者都是无符号的,并且两者都应该能够保存任何指针类型,因此它们在功能上看起来相同.除了清晰度之外,是否有任何真正令人信服的理由uintptr_t(或者更好的是,a void *)而不是a size_t?在一个不透明的结构中,字段只能由内部函数处理,有没有理由不这样做?

出于同样的原因,ptrdiff_t一直是一个能够保持指针差异的签名类型,因此能够容纳大多数指针,那么它与它intptr_t有何区别?

是不是所有这些类型基本上都服务于同一功能的不同版本?如果没有,为什么?对于其中一个我不能用另一个做什么我不能做什么?如果是这样,为什么C99会在语言中添加两种基本上多余的类型?

我愿意忽略功能指针,因为它们不适用于当前的问题,但随意提及它们,因为我有一种潜在的怀疑,它们将成为"正确"答案的核心.

Ale*_*lli 231

size_t是一种可以保存任何数组索引的类型.这意味着,逻辑上,size_t应该能够保存任何指针类型

不必要!回到分段16位架构的时代,例如:一个阵列可能仅限于一个段(所以16位size_t会这样做)但是你可能有多个段(所以需要一个32位的intptr_t类型来挑选细分及其内部的偏移).我知道这些事情听起来很奇怪,在这些日子里,统一可寻址的未分段架构,但标准必须提供比"2009年正常情况"更广泛的品种,你知道! - )

  • @Chris,仅用于指针_inside相同的数组_是否明确定义以区分它们.因此,在完全相同的分段16位架构上(阵列必须位于单个段内,但两个不同的阵列可以位于不同的段中)指针必须是4个字节,但指针**差异**可能是2个字节! (28认同)
  • 关键词有"几乎*任何平台",@ Chris.一个实现可以自由地限制指向0xf000-0xffff范围的指针 - 这需要16位intptr_t但只需要12/13位ptrdiff_t. (8认同)
  • 这一点,以及其他许多人得出同样的结论,解释了`size_t`和`uintptr_t`之间的区别,但是`ptrdiff_t`和`intptr_t` - 并不是这两者都能够存储相同的范围几乎在任何平台上的价值?为什么有符号和无符号指针大小的整数类型,特别是如果`ptrdiff_t`已经用于签名指针大小的整数类型的目的. (6认同)
  • @AlexMartelli:指针差异可以是正面的也可以是负面的.该标准要求`size_t`至少为16位,但`ptrdiff_t`至少为17位(实际上这意味着它可能至少为32位). (6认同)
  • 没关系分段架构,像x86-64这样的现代架构怎么样?此架构的早期实现仅为您提供48位可寻址空间,但指针本身是64位数据类型.你可以合理解决的最大连续内存块是48位,所以我不得不想象`SIZE_MAX`不应该是2**64.这是使用平面寻址,请注意; 为了使"SIZE_MAX"与数据指针的范围不匹配,不需要分段. (3认同)
  • 所以... sizeof(size_t) <= sizeof(uintptr_t)? (2认同)

pax*_*blo 87

关于你的陈述:

"C标准保证这size_t是一种可以保存任何数组索引的类型.这意味着,逻辑上,它size_t应该能够保存任何指针类型."

这实际上是一种谬误(由于错误的推理造成的误解)(a).你可能认为后者是从前者开始的,但事实并非如此.

指针和数组索引不是一回事.设想一个将数组限制为65536个元素的符合实现但允许指针将任何值寻址到一个巨大的128位地址空间中是非常合理的.

C99表示size_t变量的上限由下定义,SIZE_MAX并且可以低至65535(参见C99 TR3,7.18.3,在C11中不变).如果在现代系统中将指针限制在此范围内,则指针将相当有限.

在实践中,您可能会发现您的假设成立,但这不是因为标准保证了它.因为它实际上并不能保证它.


(a)顺便说一下,这不是某种形式的人身攻击,只是说明为什么你的陈述在批判性思维的背景下是错误的.例如,以下推理也无效:

所有的小狗都很可爱.这件事很可爱.因此,这件事必须是一只小狗.

puppiess的可爱或其他方面在这里没有任何影响,我所说的只是两个事实并不能得出结论,因为前两个句子允许存在不是小狗的可爱东西.

这类似于你的第一个陈述,不一定强制要求第二个陈述.

  • @Ivan,与大多数沟通一样,需要对某些基本项目有共同的理解.如果你认为这个答案是"有趣的",我向你保证这是对我的意图的误解.假设你指的是我的"逻辑谬误"评论(我看不到任何其他可能性),那就是一个事实陈述,而不是一些以OP为代价的陈述.如果你想提出一些*具体的改进措施,以尽量减少误解的可能性(而不仅仅是一般的抱怨),我很乐意考虑. (5认同)
  • @Ivan,对您提议的编辑并不满意,已回滚并尝试删除任何意外的冒犯。如果您要提供任何其他更改,我建议您开始聊天,以便我们进行讨论。 (2认同)

unw*_*ind 36

我会让所有其他答案代表片段限制,异国情调架构等的推理.

名称的简单差异是不是足以使用正确的类型来做正确的事情?

如果您要存储尺寸,请使用size_t.如果您要存储指针,请使用intptr_t.阅读你的代码的人会立即知道"啊哈,这是一个大小的东西,可能以字节为单位","哦,这里的指针值由于某种原因存储为整数".

否则,您可以使用unsigned long(或者,在这些现代时代unsigned long long),用于所有事情.大小不是一切,类型名称带有有用的含义,因为它有助于描述程序.


Mic*_*urr 12

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

虽然这些在桌面计算机中不常用,但C标准旨在支持甚至小型的专用架构.例如,仍然有8或16位CPU开发嵌入式系统.

  • 阅读http://en.wikipedia.org/wiki/C_memory_model#Memory_segmentation并为死亡的MS-DOS程序员哭泣,以便我们可以自由. (7认同)

dre*_*lax 5

我想(这适用于所有类型的名称)它更好地表达了你在代码中的意图.

例如,即使unsigned short并且wchar_t在Windows上具有相同的大小(我认为),使用wchar_t而不是unsigned short显示您将使用它来存储宽字符的意图,而不仅仅是一些任意数字.