why is sizeof(ptrdiff_t) == sizeof(uintptr_t)
why is sizeof(ptrdiff_t) == sizeof(uintptr_t)
我看到了一些关于size_t与uintptr_t的帖子(如size_t与uintptr_t),但没有关于这些新的c99 ptr大小类型的相对大小。
示例机:香草ubuntu 14lts x64, GCC 4.8
printf("%zu, %zu, %zun", sizeof(uintptr_t), sizeof(intptr_t), sizeof(ptrdiff_t));
打印:" 8,8,8 "
这对我来说没有意义,因为我希望diff类型(必须带符号)比无符号PTR本身需要更多的位。
考虑:
NULL - (2^64-1) /*largest ptr, 64bits of 1's.*/
如果是2的补码为负,则不适合64位;因此,我希望ptrdiff_t大于ptr_t。
[一个相关的问题是为什么intptr_t的大小与intptr_t相同....虽然我很舒服,但这可能只是为了允许有符号类型包含表示的位(例如,在负PTR上使用有符号算术将(a)未定义,并且(b)有限的效用,因为PTRS根据定义是"正")]
谢谢!
首先,很明显uintptr_t
在这里做什么。语言(C和c++)不允许您从彼此之间减去任意的指针值。只有当两个指针指向同一个对象(指向同一个数组对象)时,它们才能被减去。否则,行为是未定义的。这意味着这两个指针之间的距离不可能超过SIZE_MAX
字节。注意:距离受size_t
范围限制,不受uintptr_t
范围限制。一般情况下,uintptr_t
可以是比size_t
更大的类型。在C/c++中没有人向你保证,你应该能够减去两个相隔UINTPTR_MAX
字节的指针。
(是的,我知道在平面内存平台上uintptr_t
和size_t
通常是相同的类型,至少在范围和表示上是这样。但从语言的角度来看,假设它们总是如此是不正确的。
你的NULL - (2^64-1)
(如果解释为地址减法)是这种可疑减法的一个明显例子。一开始是什么让你觉得你可以这么做的?
其次,在从不相关的uintptr_t
切换到更相关的size_t
之后,可以说你的逻辑是完全有效的。sizeof(ptrdiff_t)
应该大于sizeof(size_t)
,因为需要一个额外的位来表示带符号的结果。然而,无论这听起来多么奇怪,语言规范并不要求ptrdiff_t
足够宽以容纳所有指针减法结果,即使两个指针指向同一对象的部分(即它们之间的距离不超过SIZE_MAX
字节)。ptrdiff_t
与size_t
具有相同的比特计数。
这意味着一个"看似有效"的指针减法实际上可能仅仅因为结果太大而导致未定义的行为。如果您的实现允许您声明大小为char
的数组,例如,SIZE_MAX / 3 * 2
char array[SIZE_MAX / 3 * 2]; // This is smaller than `SIZE_MAX`
如果ptrdiff_t
与size_t
具有相同的大小,那么减去指向该数组末尾和开始的完全有效的指针可能会导致未定义的行为
char *b = array;
char *e = array + sizeof array;
ptrdiff_t distance = e - b; // Undefined behavior!
这些语言的作者决定选择这个更简单的解决方案,而不是要求编译器实现对[可能是非本地的]extra - wide signed integer类型ptrdiff_t
的支持。
现实生活中的实现意识到这个潜在的问题,并且通常采取措施来避免它。它们人为地限制了支持的最大对象的大小,以确保指针减法永远不会溢出。在一个典型的实现中,你将不能声明一个大于PTRDIFF_MAX
字节的数组(大约是SIZE_MAX / 2
)。例如,即使您的平台上的SIZE_MAX
是264-1,实现也不会允许您声明大于263-1字节的任何内容(并且来自其他因素的现实限制可能比这更严格)。有了这个限制,任何合法的指针减法都将产生符合ptrdiff_t
范围的结果。
也看到,
- 为什么数组的最大大小"太大"?
公认的答案是正确的,但是并没有深入了解为什么intptr_t、size_t和ptrdiff_t实际上是有用的,以及如何使用它们。这里是:
-
size_t
基本上是size_of
表达的类型。它只需要能够保存您可以创建的最大对象的大小,包括数组。因此,如果您只能使用64k的连续内存,那么size_t可以小到16位,即使您有64位指针。 -
ptrdiff_t
为指针差值类型,如&a - &b
。虽然0 - &a
确实是未定义的行为(就像在C/c++中做几乎所有事情一样),但无论它是什么,都必须适合ptrdiff_t
。它通常与指针的大小相同,因为这是最有意义的。如果ptrdiff_t
是一个奇怪的大小,指针运算本身就会中断。 -
intptr_t
/uintptr_t
的大小与指针相同。它们符合相同的int*_t
模式,其中*是int类型的大小。与所有int*_t
/uint*_t
类型一样,由于某种原因,标准允许它们比所需的大,但这种情况非常罕见。
根据经验,您可以使用size_t
来处理大小和数组索引,并使用intptr_t
/uintptr_t
来处理与指针相关的所有内容。不要使用ptrdiff_t
- 如何使我的 sizeof sum 结构与空参数包一起工作
- 同一对象的"sizeof"的不同答案
- 为什么数组大小信息可用于"sizeof"运算符和 delete[] 运算符,但在将数组作为参数传递到
- 为什么 sizeof 在 C++ 中给出不正确的字节数?
- sizeof(size_t) 可以小于 sizeof(int) 吗?
- 字符串数组上的 sizeof 运算符以 C++ 为单位给出不同的输出
- 为什么 sizeof(ar)/ sizeof(ar[0]) 在传递给函数时无法在向量上正常工作?
- 为什么 MSVC _count_of实现将 0 添加到 sizeof 的结果中?
- alignas() 对 sizeof() 的影响 - 强制性的?
- 在C++中,运算符 sizeof 返回什么数据类型?
- sizeof 函数如何在带和不带位字段的结构上工作?(填充)
- s.length 和 sizeof(a) 有什么区别?
- sizeof(enum) 可以不同于 sizeof(std::underlying_type<Enum>::
- 如何将数组传递给使用 sizeof 的函数?
- sizeof(size_t) 和 sizeof(ptrdiff_t) 什么时候会有所不同?
- " sizeof "操作员在编程中真的很重要吗,尤其是在构建大型应用程序时?
- 在QScopedPointer的实现中使用sizeof
- Sizeof返回的是指针大小,而不是数组大小.有其他方法可以找到尺寸吗
- 为什么sizeof函数在这里不能正常工作
- 在 T 的静态成员中使用 sizeof(T) 的 c++ 错误