C語言之大小端問題

1:大小端名字的由來及發展面試

  (1)在喬納森·斯威夫特的著名諷刺小說《格列夫遊記》中,小人國內部分裂成Big-endian和Little-endian兩派,區別在於一派要求從雞蛋的大頭把雞蛋打破,另外一派要求從雞蛋的小頭把雞蛋打破。斯威夫特藉以諷刺英國的政黨之爭,在計算機工業中指數據儲存順序的分歧。ide

     (2)後來計算機通訊發展起來後,遇到一個問題就是:在串口等串行通訊中,一次只能發送1個字節。這時候我要發送一個int類型的數就遇到一個問題。int類型有4個字節,我是按照:byte0 byte1 byte2 byte3這樣的順序發送,仍是按照byte3 byte2 byte1 byte0這樣的順序發送。規則就是發送方和接收方必須按照一樣的字節順序來通訊,不然就會出現錯誤。這就叫通訊系統中的大小端模式。這是大小端這個詞和計算機掛鉤的最先問題。測試

  (3)如今咱們講的這個大小端模式,更可能是指計算機存儲系統的大小端。在計算機內存/硬盤/Nnad中。由於存儲系統是32位的,可是數據仍然是按照字節爲單位的。因而乎一個32位的二進制在內存中存儲時有2種分佈方式:高字節對應高地址(大端模式)、高字節對應低地址(小端模式)spa

   (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;
}

分析:it

  首先共用體元素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,則說明當前機器是大端模式(這種測試方法要記住,面試時候常常考)io

2.2:指針方式來測試大小端編譯

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:強制類型轉換

這裏就再也不次分析, 實際測試時不行的,緣由同上

相關文章
相關標籤/搜索