大端字節(big-endian)和小端字節(little-endian)

大小字節序問題
2008-09-23 00:53
二進制文件的字節順序問題:
大端字節(big-endian)和小端字節(little-endian)
    今天碰一個關於字節順序的問題,雖然看起來很簡單,但一直都沒怎麼徹底明白這個東西,索性就找了下資料,把它弄清楚.
    由於現行的計算機都是以八位一個字節爲存儲單位,那麼一個16位的整數,也就是C語言中的short,在內存中可能有兩種存儲順序big-endian和litte-endian.
    考慮一個short整數0x3132(0x32是低位,0x31是高位),把它賦值給一個short變量,那麼它在內存中的存儲可能有以下兩種狀況:
大端字節(Big-endian):
----------------->>>>>>>>內存地址增大方向
short變量地址
       0x1000                  0x1001
_____________________________
|                           |
|         0x31             |       0x32
|________________ | ________________
高位字節在低位字節的前面,也就是高位在內存地址低的一端.能夠這樣記住(大端->高位->在前->正常的邏輯順序)
小端字節(little-endian):
----------------->>>>>>>>內存地址增大方向
short變量地址
       0x1000                  0x1001
_____________________________
|                           |
|         0x32             |       0x31
|________________ | ________________
低位字節在高位字節的前面,也就是低位在內存地址低的一端.能夠這樣記住(小端->低位->在前->與正常邏輯順序相反)
能夠作個實驗
在windows上下以下程序
#include
#include !@#$%^&*,見鬼去吧 -_-|||
     爲何要注意字節序的問題呢?你可能這麼問。固然,若是你寫的程序只在單機環境下面運行,而且不和別人的程序打交道,那麼你徹底能夠忽略字節序的存在。但 是,若是你的程序要跟別人的程序產生交互呢?在這裏我想說說兩種語言。C/C++語言編寫的程序裏數據存儲順序是跟編譯平臺所在的CPU相關的,而 JAVA編寫的程序則惟一採用big endian方式來存儲數據。試想,若是你用C/C++語言在x86平臺下編寫的程序跟別人的JAVA程序互通時會產生什麼結果?就拿上面的 0x12345678來講,你的程序傳遞給別人的一個數據,將指向0x12345678的指針傳給了JAVA程序,因爲JAVA採起big endian方式存儲數據,很天然的它會將你的數據翻譯爲0x78563412。什麼?居然變成另一個數字了?是的,就是這種後果。所以,在你的C程序 傳給JAVA程序以前有必要進行字節序的轉換工做。
     無獨有偶,全部網絡協議也都是採用big endian的方式來傳輸數據的。因此有時咱們也會把big endian方式稱之爲網絡字節序。當兩臺採用不一樣字節序的主機通訊時,在發送數據以前都必須通過字節序的轉換成爲網絡字節序後再進行傳輸。ANSI C中提供了下面四個轉換字節序的宏。
這裏有一段W. Richard Stevens的代碼,用於判斷字節序
/*
* gcc -Wall -pipe -O3 -s -o byte_order byte_order.c
*/
#include
#include
/*
* return value:
* 1 big-endian
* 2 little-endian
* 3 unknow
* 4 sizeof( unsigned short int ) != 2
*/
static int byte_order ( void )
{
union
{
unsigned short int s;
unsigned char c[ sizeof( unsigned short int ) ];
} un;
un.s = 0x0201;
if ( 2 == sizeof( unsigned short int ) )
{
if ( ( 2 == un.c[0] ) && ( 1 == un.c[1] ) )
{
puts( "big-endian" );
return( 1 );
}
else if ( ( 1 == un.c[0] ) && ( 2 == un.c[1] ) )
{
puts( "little-endian" );
return( 2 );
}
else
{
puts( "unknow" );
return( 3 );
}
}
else
{
printf( "sizeof( unsigned short int ) = %u\n", ( unsigned int )sizeof(unsigned short int ) );
return( 4 );
}
return( 3 );
} /* end of byte_order */
int main ( int argc, char * argv[] )
{
printf( "byte_order() = %d\n", byte_order() );
return( EXIT_SUCCESS );
} /* end of main */
小端方式每一個字的低位字節在低地址,而大端方式每一個字的低位字節在高地址,所以小端存儲順序是正常的,大端存儲順序是相反的。
可是在調試器中,若是按照地址遞增的方式看過去,小端格式的內容是很是彆扭的,而大端格式是正常的順序。
例如0x12345678小端方式存放以下:
地址                      內容
A                          78
A+1                        56
A+2                        34
A+3                        12
大端方式存放以下:
地址                      內容
A                          12
A+1                        34
A+2                        56
A+3                        78
大端和小端字節序的問題在網絡中以及在不一樣的操做系統的兼容性中是一個比較大的問題。它關係到不一樣操做系統和網絡傳輸是否可以保證數據的語義正確性。
    對於一個字節而言,大端和小端沒有任何的區別,可是對於多個字節而言,就存在着顯著的區別。這個區別咱們能夠很容易想到,若是提供了一個地址,好比 0x37041200,須要讀取這個地址的一個字,也就是4個字節的一個數據。那麼是讀取從0x37041200開始到0x37041300這樣的一個 數,仍是讀取從0x37041200開始到0x37041100存儲的4個字節的數。爲此就出現了不一樣公司的兩種實現--一個就是大端,一個就是小端。
----------------------------------------------------------
假設:a=0x12345678;
則大端字節序和小端字節序的存儲以下圖所示:
                 Big-Endian                               Little-Endian
0字節            12h                                       78h
1字節            34h                                       56h
2字節            56h                                       34h
3字節            78h                                       12h
h表示16進制
小端:低位字節在高位字節的前面,也就是低位在內存地址低的一端.能夠這樣記住(小端->低位在前->與正常邏輯順序相反)
你也能夠用下面的程序測驗你的機器是大端字節序仍是小端字節序:
----------------------------------------------------------
#include
int IsLittleEndian()
{
unsigned int usData = 0x12345678;
unsigned char *pucData = (unsigned char*)&usData;
if(*pucData == 0x78)
     return 1;
else
     return 0;
}
int main(void)
{
    if(IsLittleEndian())
        printf("is little endian!\n");
    else
        printf("is big endian!\n");
    return 0;
}
個人機器是Intel的X86系列,因此是little endian.
----------------------------------------------------------
a=0x12345678
The Basics
"Little Endian" means that the low-order byte of the number is stored in memory at the lowest address, and the high-order byte at the highest address. (The little end comes first.) For example, a 4 byte LongInt
    Byte3 Byte2 Byte1 Byte0
will be arranged in memory as follows:
    Base Address+0   Byte0     78h   
    Base Address+1   Byte1     56h
    Base Address+2   Byte2     34h
    Base Address+3   Byte3     12h
Intel processors (those used in PC's) use "Little Endian" byte order.
"Big Endian" means that the high-order byte of the number is stored in memory at the lowest address, and the low-order byte at the highest address. (The big end comes first.) Our LongInt, would then be stored as:
    Base Address+0   Byte3        12h
    Base Address+1   Byte2      34h
    Base Address+2   Byte1      56h
    Base Address+3   Byte0      78h
Motorola processors (those used in Mac's) use "Big Endian" byte order
Little Endian    Base Address(BA)指向數據的低位
              ------->    
            |--|--|--|--|
            |78|56|34|12|
            |--|--|--|--|
            BA   
            |--|--|--|--|
            |12|34|56|78|
            |--|--|--|--|
相關文章
相關標籤/搜索