关于数据存储大小端模式的C语言题目

int main()
{
    int a[5]={1,2,3,4,5};
    int *ptr1=(int *)(&a+1);
    int *ptr2=(int *)((int)a+1);
    printf("%x,%x",ptr1[-1],*ptr2);
    return 0;
}
首先附上1张图片,该图片是我在验证的时候数据的存储方式。


这道C语言的题目看似简单,但是涉及的C语言的知识点还是很多的,比如,指针,强制类型转化,并且这里的的强制类型转换还和地址相关,
以及操作系统的大小端模式,数组名的含义等等。
分析:
1行代码:这行代码定义并初始化了一个数组
2行代码:将这行代码分解开来会好理解一些,&a的理解:a是数组名,是数组首元素的地址,也就是&a[0]的值,这个值是整个数组的首地址,
所以&a数值上和&a[0]一样,但是代表的意义不一样,(&a[0]+1)表示的是a[1]这个元素的地址,但是(&a+1)表示确实跨过这个数组的那个地址,
也就是元素a[4]所在地址后面的那个地址,证明如下:

int main()
{
   int a[5]={1,2,3,4,5};
   printf("&a[0]=%p\n",&a[0]);
   printf("&a[0]+1=%p\n",&a[0]+1);
   printf("&a[4]=%p\n",&a[4]);
   printf("&a[4]+1=%p\n",&a[4]+1);
   printf("&a=%p\n",&a);
   printf("&a+1=%p\n",&a+1);
   return0;
}
结果:
&a[0]=0060FF10
&a[0]+1=0060FF14
&a[4]=0060FF20
&a[4]+1=0060FF24
&a=0060FF10
&a+1=0060FF24


(int *)(&a+1)的理解:根据上面得到的结论,&a+1=0060FF24,表示的是一个地址一样的数值,通过int*强制转换为地址。
int *ptr1=(int *)(&a+1)的理解:定义int类型的指针变量prt1指向(int *)(&a+1)所代表的地址,也就是&a+1=0060FF24
这个地址,显然这个地址是数组的最后一个元素的地址的下一个地址


ptr1[-1]的理解:数组下标是可以为负数的,实际上,取下标符“[ ]”的内部实现,就是指针运算!比如a[2],等价于*(a+2),
即以a地址为基址,取偏移量为2的地址的值。所以ptr1[-1]等价于*(ptr1-1)。那么printf("%x ",ptr1[-1]);的结果是就是在
0060FF24地址的基础上向前移动一个int大小的空间,并指向0060FF20地址里的内容也就是a[4]=5.


3行代码的分析; (int)a是把地址类型强行转换为int类型的数组,同时+1,注意,这里的1默认是int类型
(C规定整数默认int类型,小数默认double类型,在很大程度上是为了保证精度),所以(int)a+1就是在0060FF10的基础上+1
也就是0060FF11。int *ptr2=(int *)((int)a+1)的理解:看完之前的文字再看这里不难看出,ptr2指向0060FF11这个地址,
因为是int类型的指针,所以将0060FF11之后的连续四个地址理解为一个地址空间,0060FF11,0060FF12,0060FF13,0060FF14,
其中0060FF11,0060FF12,0060FF13,这三个地址里面的数字为0,0060FF14地址里的数值为2,那么这几个地址如何安排组成
一个int类型的数字呢,这道题之所以强调x86系统就是因为这个操作系统采用的是小端模式存数据的,所以之前的所有结论也都
是基于这个所说,如果是大端模式的存储方式,上面的结论也就不对了。既然是按照小端模式(little_endian)存储的也就是
高字节的数据存数在高地址,低字节存储在低地址,所以*ptr2指向的就是由0060FF11,0060FF12,0060FF13,0060FF14这四个
字节组成的int数据,很明显这个int型的数据就是0x02000000


所以上面的题目的打印结果就是5,2000000

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章