問題引入
加3g實驗室的艱難之旅,遇到一道這樣的實驗室面試題:
閱讀以下代碼,計算結(jié)果。
int main(){
int a[5] = {1,2,3,4,5};
int *ptr2 = (int *)((long int)a+1);
printf("%x",*ptr2);
return 0;
}
** 輸出結(jié)果為2000000 **
原題對a強(qiáng)制轉(zhuǎn)換為int,64位機(jī)指針長度為八個字節(jié),所以改為long int。
先來分析一下表達(dá)式,a為數(shù)組a[0]的地址,強(qiáng)制轉(zhuǎn)換為長整型變?yōu)榈刂返臄?shù)值后加一,實際為第一個元素的第二字節(jié)地址的數(shù)值。后轉(zhuǎn)換為一指向整型的指針并賦值給ptr2。整型為4個字節(jié),從第一元素第二字節(jié)開始往后讀取四個字節(jié),間接訪問得出此四個字節(jié)代表的數(shù)值,并以十六進(jìn)制輸出。
那么問題來了,為什么是2000000,數(shù)組的整型元素在內(nèi)存中是怎么儲存的?這四個字節(jié)內(nèi)存的是怎樣的二進(jìn)制數(shù)?為什么會這樣儲存?
經(jīng)過度娘的幫助,它終于出現(xiàn)了——大小端模式。
什么是大小端模式
大端模式
大端模式是指數(shù)據(jù)的高位,保存在內(nèi)存的低地址中,而數(shù)據(jù)的低位,保存在內(nèi)存的高地址中。大端模式與我們的閱讀習(xí)慣相同。
小端模式
小端模式是指數(shù)據(jù)的高位保存在內(nèi)存的高地址中,而數(shù)據(jù)的低位保存在內(nèi)存的低地址中。
舉例
int a=2;
地址:小----->大
在大端模式中,a存為:
0x00 0x00 0x00 0x02
在小端模式中,a存為:
0x02 0x00 0x00 0x00
為什么會有大小端模式
在計算機(jī)系統(tǒng)中,地址是以字節(jié)為單位的,每個地址單元都對應(yīng)著一個字節(jié),一個字節(jié)為8bit。但是在C語言中除了一個字節(jié)(8bit)的char之外,還有兩個字節(jié)(16bit)的short型等超過一個字節(jié)的數(shù)據(jù)類型。另外,對于位數(shù)大于 8位的處理器,由于寄存器寬度大于一個字節(jié)。所以必然存在如何將多個字節(jié)安排的問題,因此就有了大端存儲模式和小端存儲模式。
呀哈名字由來
小說《格列夫游記》中,小人國內(nèi)部分裂成Big-endian和Little-endian兩派,區(qū)別在于一派要求從雞蛋的大頭把雞蛋打破,另一派要求從雞蛋的小頭把雞蛋打破。斯威夫特借以諷刺英國的政黨之爭,在計算機(jī)工業(yè)中指數(shù)據(jù)儲存順序的分歧。
測試大小端
一個簡單的判斷數(shù)據(jù)儲存模式為大端模式還是小端模式。
#include<stdio.h>
int main(){
int x = 1;
char *p = (char *)&x;
if(*p) printf("little\n");
else printf("big\n");
return 0;
}
回歸面試題
a[5] = {1,2,3,4,5};
第一個元素和第二個元素儲存方式
(地址:小--->大)
大端模式下:
0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x02
小端模式下:
0x01 0x00 0x00 0x00 0x02 0x00 0x00 0x00
截取第二個字節(jié)到第五個字節(jié)
大端模式:
0x00 0x00 0x01 0x00
小端模式:
0x00 0x00 0x00 0x02
讀取數(shù)據(jù)
大端模式:
從高地址往低地址讀取
0x00 0x00 0x01 0x00
讀取數(shù)據(jù)轉(zhuǎn)換為十六進(jìn)制為100
小端模式:
從低地址往高地址讀取
0x00 0x00 0x00 0x02
排成大端(0x02 0x00 0x00 0x00)
讀取數(shù)據(jù)轉(zhuǎn)換為十六進(jìn)制為2000000
所以在大端模式下,結(jié)果為100。
在小端模式下,結(jié)果為2000000。
學(xué)C學(xué)得好迷啊,心好累,哈哈哈哈哈。