减去两个指针,给出意想不到的结果

#include  int main() { int *p = 100; int *q = 92; printf("%d\n", p - q); //prints 2 } 

上述程序的输出不应该是8吗?

相反,我得到2。

除了未定义的行为,这是您使用指针算法获得的行为:当减去指针是合法的时,它们的差异表示指针之间的数据项的数量。 在int情况下,在你的系统上每个int使用四个字节,相隔八个字节的指针之间的差异是(8 / 4) ,这可以达到2

这是一个没有未定义行为的版本:

 int data[10]; int *p = &data[2]; int *q = &data[0]; // The difference between two pointers computed as pointer difference ptrdiff_t pdiff = p - q; intptr_t ip = (intptr_t)((void*)p); intptr_t iq = (intptr_t)((void*)q); // The difference between two pointers computed as integer difference int idiff = ip - iq; printf("%td %d\n", pdiff, idiff); 

演示。

这个

 int *p = 100; int *q = 92; 

已经无效C.在C中,您无法初始化具有任意整数值的指针。 除了从空指针常量0转换之外,语言中没有隐式的整数到指针转换。 如果由于某种原因需要将特定的整数值强制转换为指针,则必须使用显式转换(例如int *p = (int *) 100; )。

即使你的代码以某种方式编译,其行为也不是由C语言定义的,这意味着这里没有“应该”的答案。

您的代码是未定义的行为 。

你不能简单地减去两个“任意”指针。 引用C11 ,章节§6.5.6/ P9

当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素; 结果是两个数组元素的下标的差异。 结果的大小是实现定义的,其类型(有符号整数类型)是在头中定义的ptrdiff_t 。 [….]

另外,如上所述,如果正确地减去两个指针,结果将是ptrdiff_t类型,您应该使用%td来打印结果。


那就是说,初始化

  int *p = 100; 

本身看起来很错!! 为了澄清,它不会将值100存储到指向的内存位置( 问题:它指向哪里?p 。 它试图用整数值100设置指针变量本身,这似乎是一个约束违反本身。

根据标准( N1570 )

当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素; 结果是两个数组元素的下标的差异。

这些是整数指针, sizeof(int)是4.指针算术以指向的东西的大小为单位完成。 因此,以字节为单位的“原始”差异除以4.此外,结果是ptrdiff_t因此%d不太可能削减它。

但请注意,正如Sourav指出的那样,你所做的是技术上未定义的行为。 它几乎是偶然地在最常见的环境中工作。 但是,如果p和q指向同一个数组,则定义行为。

 int a[100]; int *p = a + 23; int *q = a + 25; printf("0x%" PRIXPTR "\n", (uintptr_t)a); // some number printf("0x%" PRIXPTR "\n", (uintptr_t)p); // some number + 92 printf("0x%" PRIXPTR "\n", (uintptr_t)q); // some number + 100 printf("%ld\n", q - p); // 2 
 int main() { int *p = 100; int *q = 92; printf("%d\n", p - q); //prints 2 } 

它被称为pointer arthmetic那里发生了什么。

该值将为(100-92)/sizeof(int) 。 在你的情况下sizeof(int)=4

在ISO9899中,指针运算被定义为减法ptr-ptr 。 第6.5.6p9章

当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素; 结果是两个数组元素的下标的差异。