在整数中存储指针差异?

时间:2013-08-07 16:35:53

标签: c pointers pointer-arithmetic

这是代码:

#include<stdio.h>
#include<conio.h>

int main()
{
    int *p1,*p2;
    int m=2,n=3;
    m=p2-p1;
    printf("\np2=%u",p2);
    printf("\np1=%u",p1);   
    printf("\nm=%d",m);       
    getch();
    return 0;
}

这将输出为:

p2= 2686792
p1= 1993645620
m= -497739707

我对代码和输出有两个疑问:

  1. 由于'm'是一个int,它不应该将p2-p1作为输入,因为p1和p2都是指针而m是一个整数,它应该给出一个错误,如“从'int'无效转换'int'“但不是。为什么呢?

  2. 即使在输入后,差异也无效。为什么?

2 个答案:

答案 0 :(得分:1)

  

因为'm'是一个int,所以不应该将p2-p1作为输入,因为p1和    p2都是指针,m是一个整数,它应该给出一个错误   “从'int'无效转换为'int'”但事实并非如此。为什么?

此类错误或警告取决于您使用的编译器。 C编译器经常给程序员提供足够的绳索让自己挂起......

  

即使在输入后,差异也无效。为什么?

实际上,差异是正确的!它正在使用pointer arithmetic来执行计算。所以对于这个例子..

p2 = 2686792

p1 = 1993645620

由于指针未初始化,因此会为它们分配一些垃圾值,如上所述。现在,您想执行操作p2 - p1,即。你要的是在p2 之前恰好是p1内存块的内存地址。由于p1和p2是整数的指针,因此内存块的大小为sizeof(int)(几乎总是4个字节)。因此:

p2 - p1 =(2686792 - 1993645620)/ sizeof(int) =(2686792 - 1993645620)/ 4 = -497739707

答案 1 :(得分:0)

  

由于'm'是一个int,它不应该把p2-p1作为输入,因为p1和p2都是指针而m是一个整数,它应该给出一个错误,比如“从'int'无效转换为'int “但事实并非如此。为什么呢?

C ++规范声明这是合法的 从C ++ 11规范5.7.6:

  

当减去指向同一数组对象的元素的两个指针时,结果是两个数组元素的下标的差异。结果的类型是实现定义的有符号整数类型;此类型应与标题(18.2)中定义为std :: ptrdiff_t的类型相同。

......在该段后面......

  

除非两个指针都指向同一个数组对象的元素,否则   在数组对象的最后一个元素之后,行为未定义。

p2-p1的结果与std :: ptrdiff_t的类型相同,但没有任何说明编译器不能将其定义为

namspace std {
    typedef ptrdiff_t int;
}

但是,您也没有得到保证,这将适用于所有平台。例如,某些平台(尤其是64位平台)将使用long for ptrdiff_t。在这些平台上,您的代码将无法编译,因为它依赖于ptrdiff_t的实现定义类型。

关于你的第二个问题,C ++规范5.7.6中的措辞表明了它们的工作方式。措辞表明该语言的编写者需要指针算法来支持快速算术,同时通过数组工作。因此,当在操作数组的上下文中使用时,定义了指针减法的结果以产生方便的结果。您可以构建一种语言,其中两个指针之间的差异是它们的内存地址之间的差异(以字节为单位),并且您将拥有一致的工作语言。然而,一个好的语言总能获得最好的帮助。作者认为,对阵列进行干净的操作比获得字节差异更有价值。例如:

double* findADouble(double* begin, double* end, double valueToSearchFor)
{
    for (double* iter = begin; iter != end; iter++) {
        if (*iter == valueToSearchFor)
            return iter;
    }
    return 0;
}

必须有一个sizeof,我们必须使用+ =而不是++。

double* findADouble(double* begin, double* end, double valueToSearchFor)
{
    for (double* iter = begin; iter != end; iter += sizeof(double)) {
        if (*iter == valueToSearchFor)
            return iter;
    }
    return 0;
}

在他们的决定中也值得注意:当在C中创建规则时,优化编译器的工作并不是很好。 iter + = sizeof(double)可以编译成比++ iter低得多的汇编代码,即使这两个操作从根本上做同样的事情。现代优化器对此没有任何问题,但语法仍然存在。