關於數據存儲大小端模式的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

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