这是C标准中的相关段落:
6.5.6 加法运算符
[...]
语义
[...]
9. 当两个指针相减时,两个指针都应指向同一个数组对象的元素,或者指向数组对象的最后一个元素;结果是两个数组元素的下标之差。结果的大小由实现定义,其类型(有符号整数类型)ptrdiff_t
在标头中定义<stddef.h>
。如果结果在该类型的对象中不可表示,则行为未定义。换句话说,如果表达式P
和Q
分别指向数组对象的i
第 -th 和-th 元素,则表达式具有值,前提是该值适合类型的对象j
(P)-(Q)
i - j
ptrdiff_t
. 此外,如果表达式P
指向数组对象的一个元素或数组对象的最后一个元素,并且表达式Q
指向同一数组对象的最后一个元素,则表达式具有与和 as((Q)+1)-(P)
相同的值,并且如果表达式指向数组对象的最后一个元素后一个,则其值为零,即使表达式不指向数组对象的元素也是如此。108)((Q)-(P))+1
-((P)-((Q)+1))
P
(Q)+1
108) 处理指针运算的另一种方法是首先将指针转换为字符指针:在此方案中,添加到转换后的指针或从转换后的指针中减去的整数表达式首先乘以最初指向的对象的大小, 并将结果指针转换回原始类型。对于指针减法,字符指针之间的差异的结果类似地除以最初指向的对象的大小。以这种方式来看,实现只需要在对象结束后提供一个额外的字节(可能与程序中的另一个对象重叠),以满足“最后一个元素”的要求。
尽管 C 标准没有强制要求,但ptrdiff_t
通常定义为大小与size_t
. 在对象的最大大小限制为 32 位的体系结构上,例如 32 位 Windows 和 Unix 系统,size_t
是无符号 32 位整数类型和ptrdiff_t
有符号 32 位整数类型,而在具有更大的地址空间,它们都是 64 位整数类型,有符号ptrdiff_t
和无符号size_t
。
但是请注意,两个指针在一个非常大的数组中的差异char
可能会超出与 . 相同大小的有符号类型的范围size_t
。例如,一个 3GB 的 char 数组可能在 32 位系统(UINT32_MAX
> 3GB)上可用,但 2 个指针的绝对值之差可能高达 3GB,超出了 的范围int32_t
,因此适合ptrdiff_t
该平台的类型,调用未定义的行为。
大多数实现通过减去地址并将结果除以元素大小来获得差值,如果大小是 2 的幂,则使用有符号算术或有符号右移。这可能会产生不正确char
的结果value 适合 type 的对象ptrdiff_t
。
使用实现定义类型ptrdiff_t
而不是实现定义类型的基本原理long long
是保持与现有实现的兼容性,并避免在地址空间较小的系统上使用较大的类型,这会导致空间和时间上的额外开销。在早期的 C 实现中,该类型int
被用于此目的,当size_t
引入可能与 不同的范围时,由于 2 个指针的差异太小unsigned int
,因此需要使用特定类型。可能仍然太小,但仅适用于边境情况。int
ptrdiff_t