1. 程式人生 > 其它 >計算機的大小端

計算機的大小端

計算機的大小端指的是不同的位元組順序儲存方式。

0x1A2B3C4D,總共四個位元組,兩個十六進位制數表示一個位元組,高位位元組為0x1A,低位位元組為0x4D;中間兩個位元組分別為0x2B和0x3C;數值0x1A2B3C4D想要在計算機中正確使用,就必須要考慮在記憶體中將其對應的四個位元組合理儲存。

對於一個數值多個位元組順序儲存就有兩種儲存方式:

  • 大端:(Big-Endian):就是把數值的高位位元組放在記憶體的低位地址上,把數值的低位位元組放在記憶體的高位地址上(低位元組在後,高位元組在前)
    • 人類習慣讀寫大端位元組序,比如1234 -> 一千兩百三十四。
    • 除了計算機的內部處理,其他的場合幾乎都是大端位元組序,比如網路傳輸和檔案儲存
    • 優點:符號位的判定固定為第一個位元組,容易判斷正負。高位位元組也容易進行大小對比
舉例:
記憶體低地址 --------------------> 記憶體高地址
0x1A | 0x2B | 0x3C | 0x4D
高位位元組 <-------------------- 低位位元組
  • 小端:Little-Endian):就是把數值的高位位元組放在高位的地址上,低位位元組放在低位地址上(低位元組在前,高位元組在後)
    • 為什麼會有小端位元組序?計算機電路先處理低位位元組,效率比較高,因為計算都是從低位開始的。所以,計算機的內部處理都是小端位元組序。
    • 123 + 342 -> 先從個位開始算,再十位,百位
    • 優點:強制轉換資料不需要調整位元組內容,1、2、4位元組的儲存方式一樣。
舉例:
記憶體低地址 --------------------> 記憶體高地址
0x4D | 0x3C | 0x2B | 0x1A
低位位元組 --------------------> 高位位元組

注意:

  1. 不管是大端法還是小端法儲存,計算機在記憶體中存放資料的順序都是從地址到高地址所不同的是首先取低位元組的資料存放在低地址還是取高位元組資料存放在低地址。
  2. 大小端是資料在儲存時的表現,而不是在暫存器中參與運算時的表現
  3. 計算機處理位元組序的時候,不知道什麼是高位位元組,什麼是低位位元組,也並不存在所謂的資料型別,比如char,int等。它只知道按順序讀取
    位元組,先讀第一個位元組,再讀第二個位元組,
    如果是大端位元組序,先讀到的就是高位位元組,後讀到的就是低位位元組。小端位元組序正好相反
  4. 所謂的資料型別,比如char,int等,在程式碼中的作用就是讓編譯器知道每次應該從那個地址起始讀取多少位的資料,賦值給相應的變數

舉例,16位整數:

buf是整個資料塊在記憶體中的起始地址,offset是當前正在讀取的位置

大端:第一個位元組((高位位元組)左移8位(即後面添8個0),然後再與第二個位元組進行或運算。

x = buf[offset] << 8 | buf[offset+1];

小端:第二個位元組左移8位,然後再與第一個位元組(低位位元組)進行或運算。

x = buf[offset+1] << 8 | buf[offset];

如何用程式碼檢測用的是大端還是小端

  • 藉助聯合體union的特性實現(union型別資料所佔的記憶體空間等於其最大的成員所佔的空間,
int main(){
    union{
      int a;  //4 bytes      
      char b; //1 byte    
    } data;

    data.a = 1; //佔4 bytes,十六進位制可表示為 0x 00 00 00 01高位元組->低位元組
                     //b因為是char型只佔1Byte,a因為是int型佔4Byte   
                     //所以,在聯合體data所佔記憶體中,b所佔記憶體等於a所佔記憶體的低地址部分     
    if(1 == data.b){ //走該case說明a的低位元組,被取給到了b,即a的低位元組存在了聯合體所佔記憶體的(起始)低地址,符合小端模式特徵      
        printf("Little_Endian\n");
     } else { 0 == data.b
        printf("Big_Endian\n");
     }
   return 0;
}
  • 通過將int強制型別轉換成char單位元組,判斷起始儲存位置內容實現
int main(){
    int a = 1; //佔4 bytes,十六進位制可表示為 0x 00 00 00 01    
                   //b相當於取了a的低地址部分     
     char *b =(char *)&a; //佔1 byte    
      if (1 == *b) {//走該case說明a的低位元組,被取給到了b,即a的低位元組對應a所佔記憶體的低地址,符合小端模式特徵        
          printf("Little_Endian!\n");
    } else {
          printf("Big_Endian!\n");
    }
    return 0;
}

 

Reference:

  1. https://www.jianshu.com/p/633b52b7baec
  2. https://www.ruanyifeng.com/blog/2016/11/byte-order.html