首先,很明显不清楚为什么要在这里使用
uintptr_t
。这些语言(C和C ++)不允许您从任意指针值中减去任何指针值。只有当两个指针指向同一对象(同一个数组对象)时才可以相减。否则,行为将是未定义的。这意味着这两个指针之间的距离不可能超过
SIZE_MAX
字节。请注意:距离受
size_t
的范围限制,而不是
uintptr_t
的范围限制。在一般情况下,
uintptr_t
可以比
size_t
更大。没有人在C / C ++中保证您能够将位于
UINTPTR_MAX
字节处的两个指针相减。
(是的,我知道在平面内存平台上
uintptr_t
和
size_t
通常是相同的类型,至少在范围和表示方面是如此。但是从语言的角度来看,假设它们总是相同的是不正确的。)
其次,在从不相关的
uintptr_t
切换到更相关的
size_t
之后,可以说您的逻辑是完全有效的。
sizeof(ptrdiff_t)
应该大于
sizeof(size_t)
,因为需要一个额外的位来表示有符号结果。尽管如此,无论听起来多么奇怪,语言规范也不要求
ptrdiff_t
足够宽以容纳所有指针减法结果,即使两个指针指向同一对象的不同部分(即它们之间的距离不超过
SIZE_MAX
字节)。
ptrdiff_t
被合法地允许具有与
size_t
相同的位计数。
这意味着,“看似有效”的指针减法实际上可能会导致未定义的行为,只是因为结果太大了。如果您的实现允许您声明大小为
SIZE_MAX / 3 * 2
的
char
数组
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!
这些语言的作者选择了这种更简单的解决方案,而不是要求编译器实现对可能非本地的额外宽的带符号整数类型 ptrdiff_t
的支持。
实际的实现会意识到这个潜在的问题,并通常采取措施来避免它。他们人为地限制了最大支持对象的大小,以确保指针减法永远不会溢出。在典型的实现中,您将无法声明一个大于 PTRDIFF_MAX
字节(约为 SIZE_MAX / 2
)的数组。例如,即使您的平台上 SIZE_MAX
是 264-1,实现也不会让您声明任何大于 263-1 字节的东西(而基于其他因素得出的实际限制可能甚至更严格)。有了这个限制,任何合法的指针减法都会产生适合 ptrdiff_t
范围内的结果。
另请参见:
NULL
!如果你的意思是整数0
,请写成0
!NULL
可以表示为(void *)0
,这会导致表达式结果未定义(对空指针进行算术运算是未定义的)。 - too honest for this site