歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> C語言之大小端問題

C語言之大小端問題

日期:2017/3/1 9:09:55   编辑:Linux編程

1:大小端名字的由來及發展
(1)在喬納森·斯威夫特的著名諷刺小說《格列夫游記》中,小人國內部分裂成Big-endian和Little-endian兩派,區別在於一派要求從雞蛋的大頭把雞蛋打破,另一派要求從雞蛋的小頭把雞蛋打破。斯威夫特借以諷刺英國的政黨之爭,在計算機工業中指數據儲存順序的分歧。
(2)後來計算機通信發展起來後,遇到一個問題就是:在串口等串行通信中,一次只能發送1個字節。這時候我要發送一個int類型的數就遇到一個問題。int類型有4個字節,我是按照:byte0 byte1 byte2 byte3這樣的順序發送,還是按照byte3 byte2 byte1 byte0這樣的順序發送。規則就是發送方和接收方必須按照同樣的字節順序來通信,否則就會出現錯誤。這就叫通信系統中的大小端模式。這是大小端這個詞和計算機掛鉤的最早問題。
(3)現在我們講的這個大小端模式,更多是指計算機存儲系統的大小端。在計算機內存/硬盤/Nnad中。因為存儲系統是32位的,但是數據仍然是按照字節為單位的。於是乎一個32位的二進制在內存中存儲時有2種分布方式:高字節對應高地址(大端模式)、高字節對應低地址(小端模式)
(4)現實的情況就是:有些CPU公司用大端(譬如C51單片機);有些CPU用小端(譬如ARM)。(大部分是用小端模式,大端模式的不算多)。於是乎我們寫代碼時,當不知道當前環境是用大端模式還是小端模式時就需要用代碼來檢測當前系統的大小端。
2:測試機器大小端模式的測試代碼
2.1:使用union來測試機器的大小端
#include<stdio.h>
union myunion
{
int a;
char b;
};

int little_or_big(void)
{
myunion u1;
u1.a = 1;
return u1.b;
}
int main(void)
{
int i = little_or_big();
if(1==i)
{
printf("小端模式");
}
else
{
printf("大端模式");
}
return 0;
}


分析:
首先共用體元素a和b在訪問時候都是從低地址開始訪問的,u1.a = 1在內存中的存放有兩種可能(內存地址從左到右遞減),小端模式為 00 00 00 01;大端模式為: 01 00 00 00 ,而共用體u1中的b是char類似,所以我們用u1.b去訪問時只能讀取到最低地址的值(按char去解析時只會讀取一個字節),所以,如果讀出u1.b的值為1則說明當前機器是小端模式,讀出u1.b的值為0,則說明當前機器是大端模式(這種測試方法要記住,面試時候經常考)
2.2:指針方式來測試大小端
123456 int little_or_big2(void)
{
int a = 1;
char b = *((char *) &a);
return b;
}


分析:
首選定義變量a= 1,然後將a的指針強制類型轉換成char *接著去解應用這個指針,並賦值給b,然後根據b的返回值來確定大小端。其實分析可以發現其本質都是一樣的,都是先給一個內存裡面存一個char 類型的1,然後使得另一個char 類型的變量b去讀取這個內存的值,然後根據讀取的值來判斷大小端。
3:看似可行但實際不行的大小端測試方法
注:測試方法將測試代碼分別放在kile4.0(大端)和gcc(小端)下面去運行,看運行後的結果。

3.1:位運算
理論分析:
現在將0x1(0001)和0xf(1111)相與假設機器是大端模式,那麼相與之後得到的結果是0001;假設機器是小端模式那麼相與之後得到的結果是1000,
實際測試:
理論可行但實際上不行的,原因是位與運算是編譯器提供的運算,這個運算是高於內存層次的(或者說&運算在二進制層次具有可移植性,也就是說&的時候一定是高字節&高字節,低字節&低字節,和二進制存儲無關)
3.2:移位
理論分析:
同上假設的大端模式,那麼存儲的方式是0001,右移1位則把 1 移出去了,所以得到的結果就是0x0;假設是小端模式,那麼存儲方式是1000,右移1位,則結果是0100
實際測試:
實際不行,原因同上因為C語言對運算符的級別是高於二進制層次的。右移運算永遠是將低字節移除,而和二進制存儲時這個低字節在高位還是低位無關的。
3.3:強制類型轉換
這裡就不再次分析, 實際測試時不行的,原因同上

Copyright © Linux教程網 All Rights Reserved