请考虑以下代码段:
int *p;
/* Lets say p points to address 100
and sizeof(int) is 4 bytes. */
int *q = p+1;
unsigned long r = q-p;
/* r results in 1, hence for r = q-p
something is happening similar to r=(104-100)/4 */
在运行时是否有实际的除以sizeof(datatype)的操作,即减去了两个相同类型的指针,或者还有其他一些机制可以通过这种方式来进行指针减法。
答案 0 :(得分:3)
C standard声明了有关指针减法的内容(第6.5.6p9节):
当减去两个指针时,两个指针都应指向 同一数组对象,或在数组的最后一个元素之后 宾语; 结果是 两个数组元素。结果的大小是 实现定义的,其类型(有符号整数类型)为 标头中定义的ptrdiff_t。如果结果不是 在该类型的对象中可表示的行为是 未定义。换句话说,如果表达式P和Q指向 分别是 -th和j 如果数组对象的第n个元素适合于ptrdiff_t类型的对象,则表达式(P)-(Q)的值为ij。此外, 如果表达式P指向数组对象的元素,或者 在数组对象的最后一个元素之后,还有表达式Q 指向同一数组对象的最后一个元素,即表达式 ((Q)+1)-(P)与((Q)-(P))+ 1具有相同的值 -((P)-((Q)+1)),并且如果表达式P指向数组对象的最后一个元素的偶数,则该表达式的值为零,即使 尽管表达式(Q)+1并不指向数组的元素 宾语。 106)
脚注106指出:
另一种处理指针算法的方法是先将 指向字符指针的指针:在此方案中,整数 首先添加到转换指针或从转换指针中减去的表达式 乘以最初指向的对象的大小, 然后将结果指针转换回原始指针 类型。 对于指针相减,求和结果 字符指针之间的距离类似地除以 该对象最初指向的对象。以这种方式查看时, 实现只需要提供一个额外的字节(可能 重叠在程序中的另一个对象之后) 对象,以满足“过去一个元素过去” 要求。
因此脚注指出,可以通过减去原始指针值并除以指向的对象的大小来实现指针减法 。但是,不必以这种方式实现。
还要注意,该标准要求在指向同一数组对象的元素(或末尾的一个元素)的指针之间执行指针减法。如果没有,则行为是不确定的。在实践中,如果您正在使用具有扁平内存模型的系统,则可能仍会获得“期望”值,但您不能依赖它。
答案 1 :(得分:1)
有关指针减法工作原理的说明,请参见@dbush答案。
相反,如果您要编程的是底层代码,例如内核,驱动程序,调试器或类似程序,并且您需要对地址进行实际减法,则将指针转换为char *
:
(char *)q - (char *)p
结果将为ptrdiff_t
类型,即实现定义的带符号整数。
当然,这不是定义的/可移植的C,但是可以在大多数体系结构/环境中使用。