一道程序的分析

来源:互联网 发布:linux 查看arp 编辑:程序博客网 时间:2024/06/11 16:56

以下是程序的内容:

#include <stdio.h>  int main()  {      int a[5]={1,2,3,4,5};      int *ptr1=(int *)(&a+1);      int *ptr2=(int *)((int)a+1);      printf("0x%x,0x%x\n",ptr1[-1],*ptr2);      return 0;  } 

 在C-Free下运行的结果是:

     Ptr1[-1]的值是0x5;

     *ptr2的值是0x2000000。

1.大端模式和小端模式

        大端模式:字数据的高字节存储在低地址中,而字数据的低字节则存放在高地址中。

        小端模式:字数据的高字节存储在高地址中,而字数据的低字节则存放在低地址中。

        假设定义一个整形变量i,将它初始化为1,那么它采用大端模式存储的情况下,它在内存中的布局如图1.1所示。而它如果采用小端模式存储的情况,在内存中的布局如图1.2所示。


图1.1

图1.2

在x86模式下,CPU主要是工作在小端模式下的。而ARM则在大端模式和小端模式下都可工作。

        可以采用下面一段代码来验证当前系统采用何种存储模式:

#include "stdio.h"    int checkSystem();    int main()  {      printf("%d\n",checkSystem());  }    int checkSystem()  {      union check      {          int i;          char ch;          }c;            c.i=1;      return (c.ch==1);  }  

如果printf输出的值为1,则说明当前系统采用的存储模式为小端模式;如果输出的值为0,则说明当前系统采用的存储模式为0。

        这段判断程序的依据是:

  1. 联合体union分配了一段内存,多种不同类型的变量都可以存放到这一段内存中,也就是说,它们共同使用这一段内存。由于在union中,所有的数据成员都共同使用一段内存,所以同一时间只能存储一个数据成员,而且所有的数据成员都拥有同一个起始地址。在上面的程序中,数据成员i和ch拥有同一个起始地址。大家可以做一个试验,首先令c.i=1,然后令c.ch=2,然后分别打印这两个数据成员的值。结果是这两个数据成员的值都为2,这说明联合体union采用了覆盖的方法保证同一时间只能存储一个数据成员。
  2. 联合体union的存放顺序是所有成员都从低地址开始存放的,所以,利用这个特性,我们可以很方便地判断当前系统的存储模式。假如采用小端模式存储,当然低地址的内容就为1;采用大端模式存储,那低地址的内容就为0,而1就存储到高位地址去了。

2.数组首地址和数组首元素的首地址

     这里重申一下&a和a区别,为后面的分析准备一下。&a是指整个数组的首地址,而a则是数组首元素的首地址,即a[0]的地址。其实&a和a的值是一样的,但是两者所代表的意义是不同的,这是需要特别注意的。

3.分析ptr1和ptr2

    首先,我们来看看数组的内存地址,如图3.1。由于数组a是整型的,所以每一个数组元素占用4个字节的空间。这里a[0]~a[4]五个元素都只占用了1个字节的空间,其余的三个字节都没有使用,填充为0,如图3.1中红色的方框中所示。


图3.1

 接着,我们再看看ptr1所代表的意义。首先,ptr1是一个指针,指针的本质是地址。将(&a+1)先强制转型为与ptr1相同的类型,即int*类型,然后将它赋给变量ptr1。前面我们说过,&a代表整个数组的起始地址,那么(&a+1)所代表的就是这整个数组的下一个整型数据。因而,ptr1指向的就是现在这个数组结束以后的整型数据的空间。ptr1所指向的地址就是0x22ff34,也就是图3.1中蓝色方框中第一个字节的这个部分。ptr1[-1]会被解析成*(ptr1-1),那么ptr1-1就是后退4个字节,所指向的是0x22ff30这个地址。因此,打印出ptr1[-1]的值就是5。

       然后,我们再来分析ptr2所代表的意义。如前面所说a所代表的意义是元素a[0]的地址,那么就是0x22ff20这个地址。将a强制转型为int类型之后再加1,所代表的意义是a[0]元素的第二个字节的地址,即0x22ff21。将(a+1)再强制转型为与ptr2相同类型的int*以后赋值给ptr2,这样以后,ptr2即指向0x22ff21这个地址。那么,*ptr2就是指以0x22ff21开始的4个字节的地址中的内容,即图3.1中绿色部分所指的内容。由于x86 32位系统是以小端模式存储的,低位存储低位字节,高位存储高位字节,所以我们打印出来的结果就是0x2000000。


0 0
原创粉丝点击