您的位置:首页 > 编程语言 > C语言/C++

C、C++中指针加 1 的问题

2004-11-24 11:25 411 查看
 先用贝尔的一道笔试题简要的说明一下吧:

【题】说明以下程序。
#include <stdio.h><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

int main(void)

{

    unsigned int a[3] = {0x01020304, 0x05060708, 0x090a0b0c};
    unsigned int *p = (unsigned int *)((int)a +1);①
    printf("%x/n", *p);

    return 0;

}

【题目解析】

    这段程序的输出结果应该是 8010203(即0x08010203)。
    内存存储结构如(图1)所示(在 big-endian 的系统中)。在①处的语句中,首先把数组 a 的首地址转化为整型,然后再加 1 ,再强制转化为 (unsigned int *) ,这个时候 p 值应该是 0x1235,所以取的是从 0x1235 到 0x1238 四个字节组成的新的整数,所以就是 0x08010203。
    给出公式的话就是 (a[0]>>8 | a[1]<<24)。



图 1 内存结构示意图

【补充说明】

    看一下这条语句输出是什么呢?
        p = a;
        printf("%d  %08x  %d  %d  %d",
               (p+1)-p, *(p+1), &a[1]-&a[0],(int)(p+1)-(int)p, (char *)(p+1)-(char *)p );

    结果是: 1  05060708  1  4  4  

    第一个输出大家可能理解为理所当然了,我们先看后面的结果。

    第二个输出值是数组 a 的 a[1] 元素的值,也就是说 (p+1) 指向的地址是 0x1238,而不是0x1235。为什么呢?因为指针加 1 的时候,实际上是加上了他所指向数据类型的宽度,这样指针就可以指向下一个元素而不是一个元素的一半了。汇编代码如下:
0040106A   mov         ecx,dword ptr [ebp-10h]
0040106D   add         ecx,4                        ;注意这里,实际加的是 4,而不是1
00401070   sub         ecx,dword ptr [ebp-10h]
00401073   sar         ecx,2
00401076   push        ecx

    第三个输出按理来说应该是 0x1238-0x1234 = 4,但是为什么是 1 呢?因为返回的是这种元素的个数,而不是真正的地址差值,也就是把差值再除以元素宽度。下面是 VC 的汇编代码,参数 &a[1]-&a[0] 的压栈过程。
00401043   lea         ecx,[ebp-8]        ; 取 a[1] 的地址值
00401046   lea         edx,[ebp-0Ch]      ; 取 a[0] 的地址值
00401049   sub         ecx,edx            ; 计算地址值之差,并放入 ecx 中 (值为4)
0040104B   sar         ecx,2              ; 将 ecx 中的数值右移两位,也就是除以 4 (值为1)
0040104E   push        ecx                ; 参数压栈,供函数 printf() 使用

    第四个输出是 4,因为int类型的相减就是实际数字的相减,不需考虑其它因素,汇编代码如下:
00401063   mov         edx,dword ptr [ebp-10h]
00401066   mov         eax,dword ptr [edx+4]
00401069   push        eax                ; 注意!压栈之前没有右移操作

    第五个输出,讲到这里 我想大家应该都明白了为什么是4了,我只给出汇编代码:
0040104F   mov         eax,dword ptr [ebp-10h]
00401052   add         eax,4
00401055   sub         eax,dword ptr [ebp-10h]
00401058   push        eax

    现在在回头看一下第一个输出结果的汇编代码。在执行 p+1 的时候实际上是加了 4 (int类型的宽度),只是在减的时候将结果除了个 4,所以结果仍然是 1。
    ;(p+1)-p
0040106A   mov         ecx,dword ptr [ebp-10h]
0040106D   add         ecx,4
00401070   sub         ecx,dword ptr [ebp-10h]
00401073   sar         ecx,2
00401076   push        ecx
    

【后记】

    这些以前都有点印象,但是不是十分确定,昨天就试验了一下,找出了一下规律。其实这些 C99 上应该都有的,我同学正在帮我找,找到了将链接贴到这里。

      When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. (结果是两个数组元素的下标之差)  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息