小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Big endian and Little endian

 @IT小小鳥@ 2012-03-17
談到字節(jié)排序的問題,必然牽涉到兩大CPU派系。那就是Motorola的PowerPC系列CPU和Intel的x86系列
CPU。PowerPC系列采用big endian方式存儲(chǔ)數(shù)據(jù),而x86系列則采用little
endian方式存儲(chǔ)數(shù)據(jù)。ARM同時(shí)支持 big和little,實(shí)際應(yīng)用中通常使用little
endian。那么究竟什么是big endian,什么又是little endian呢?

其實(shí)big endian是指低地址存放最高有效字節(jié)(MSB),而little
endian則是低地址存放最低有效字節(jié)(LSB)。用文字說明可能比較抽象,下面用圖像加以說明。比如數(shù)字0x12345678在兩種不同字節(jié)序CPU中的存儲(chǔ)順序如下所示:

Big Endian
一個(gè)Word中的高位的Byte放在內(nèi)存中這個(gè)Word區(qū)域的低地址處

低地址 高地址
----------------------------------------->
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 12 | 34 | 56 | 78 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Little Endian
一個(gè)Word中的低位的Byte放在內(nèi)存中這個(gè)Word區(qū)域的低地址處

低地址 高地址
----------------------------------------->
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 78 | 56 | 34 | 12 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

從上面兩圖可以看出,采用big
endian方式存儲(chǔ)數(shù)據(jù)是符合我們?nèi)祟惖乃季S習(xí)慣的。必須注意的是:一個(gè)Word的長度是16位,一個(gè)Byte的長度是8位。如果一個(gè)數(shù)超過一個(gè)
Word的長度,必須先按Word分成若干部分,然后每一部分(即每個(gè)Word內(nèi)部)按Big-Endian或者Little-Endian的不同操作來
處理字節(jié)。
一個(gè)例子:
如果我們將0x1234abcd寫入到以0x0000開始的內(nèi)存中,則結(jié)果為
big-endian little-endian
0x0000 0x12 0xcd
0x0001 0x34 0xab
0x0002 0xab 0x34
0x0003 0xcd 0x12

需要特別說明的是,以上假設(shè)機(jī)器是每個(gè)內(nèi)存單元以8位即一個(gè)字節(jié)為單位的.簡單的說,little
endian把低位存放到高位,而big endian把低位存放到低位.
現(xiàn)在主流的CPU,intel系列的是采用的little
endian的格式存放數(shù)據(jù),而motorola系列的CPU采用的是big endian.
以下是判斷字節(jié)存儲(chǔ)順序的可移植的C語言代碼:
/*可移植的用于判斷存儲(chǔ)格式是
little endian還是big ednian的C代碼*/
#include < stdio.h >
union
{
long Long;
char Char[ sizeof ( long )];
} u;

int main()
{
u.Long = 1 ;
if (u.Char[ 0 ] == 1 )
{
printf( " Little Endian!\n " );
}
else if (u.Char[ sizeof ( long ) - 1 ] == 1 )
{
printf( " Big Endian!\n " );
}
else
{
printf( " Unknown Addressing!\n " );
}

printf( " Now, Let's look at every byte in the memory!\n " );
for ( int i = 0 ; i < sizeof ( long ); ++ i)
{
printf( " [%x] = %x\n " , & u.Char[i], u.Char[i]);
}
return 0 ;
}
在 網(wǎng)絡(luò)編程中,TCP/IP統(tǒng)一采用big
endian方式傳送數(shù)據(jù),也就是說,假設(shè)現(xiàn)在是在一個(gè)字節(jié)順序是little
endian的機(jī)器上傳送數(shù)據(jù),要求傳送的數(shù)據(jù)是0XCEFABOBO,那么你就要以0XBOBOFACE的順序在unsigned
int中存放這個(gè)數(shù)據(jù),只有這樣才能保證存放的順序滿足TCP/IP的字節(jié)順序要求.很多時(shí)候,需要自己編寫應(yīng)用層的協(xié)議,字節(jié)順序的概念在這個(gè)時(shí)候就顯
得及其的重要了.
下面給出的是在big endian和little
endian中相互轉(zhuǎn)換的代碼,C語言強(qiáng)大的位操作的能力在這里顯示了出來:
/*在little endian和big ednian之間相互轉(zhuǎn)化數(shù)據(jù)的演示代碼*/
#include < stdio.h >
const unsigned char SIZE_OF_UNSIGNEDINT = sizeof (unsigned int );
const unsigned char SIZE_OF_UNSIGNEDCHAR = sizeof (unsigned char );

void put_32(unsigned char * cmd, unsigned int data)
{
int i;
for (i = SIZE_OF_UNSIGNEDINT - 1 ; i >= 0 ; -- i)
{
cmd[i] = data % 256 ;
// 或者可以:
// cmd[i] = data & 0xFF;
data = data >> 8 ;
}
}

unsigned int get_32(unsigned char * cmd)
{
unsigned int ret;
int i;
for (ret = 0 , i = SIZE_OF_UNSIGNEDINT - 1 ; i >= 0 ; -- i)
{
ret = ret << 8 ;
ret |= cmd[i];
}
return ret;
}

int main( void )
{
unsigned char cmd[SIZE_OF_UNSIGNEDINT];
unsigned int data, ret;
unsigned char * p;
int i;
data = 0x12345678 ;
printf( " data = %x\n " , data);
// 以字節(jié)為單位打印出數(shù)據(jù)
p = (unsigned char * )( & data);
for(i = 0 ; i < SIZE_OF_UNSIGNEDINT; ++ i)
{
printf( " %x " , * p ++ );
}
printf( " \n " );
//以相反的順序存放到cmd之中
put_32(cmd, data);
for (i = 0 ; i < SIZE_OF_UNSIGNEDINT; ++ i)
{
printf( " cmd[%d] = %x\n " , i, cmd[i]);
}
// 再以相反的順序保存數(shù)據(jù)到ret中
// 保存之后的ret數(shù)值應(yīng)該與data相同
ret = get_32(cmd);
printf( " ret = %x\n " , ret);
p = (unsigned char * )( & ret);
for(i = 0 ; i < SIZE_OF_UNSIGNEDINT; ++ i)
{
printf( " %x " , * p ++ );
}
printf( " \n " );
return 0 ;
}

為什么要注意字節(jié)序的問題呢?你可能這么問。當(dāng)然,如果你寫的程序只在單機(jī)環(huán)境下面運(yùn)行,并且不和別人的程序打交道,那么你完全可以忽略字節(jié)序的存在。但
是,如果你的程序要跟別人的程序產(chǎn)生交互呢?在這里我想說說兩種語言。C/C++語言編寫的程序里數(shù)據(jù)存儲(chǔ)順序是跟編譯平臺(tái)所在的CPU相關(guān)的,而
JAVA編寫的程序則唯一采用big
endian方式來存儲(chǔ)數(shù)據(jù)。試想,如果你用C/C++語言在x86平臺(tái)下編寫的程序跟別人的JAVA程序互通時(shí)會(huì)產(chǎn)生什么結(jié)果?就拿上面的
0x12345678來說,你的程序傳遞給別人的一個(gè)數(shù)據(jù),將指向0x12345678的指針傳給了JAVA程序,由于JAVA采取big
endian方式存儲(chǔ)數(shù)據(jù),很自然的它會(huì)將你的數(shù)據(jù)翻譯為0x78563412。什么?竟然變成另外一個(gè)數(shù)字了?是的,就是這種后果。因此,在你的C程序
傳給JAVA程序之前有必要進(jìn)行字節(jié)序的轉(zhuǎn)換工作。

所有網(wǎng)絡(luò)協(xié)議也都是采用big endian的方式來傳輸數(shù)據(jù)的。所以有時(shí)我們也會(huì)把big
endian方式稱之為網(wǎng)絡(luò)字節(jié)序。當(dāng)兩臺(tái)采用不同字節(jié)序的主機(jī)通信時(shí),在發(fā)送數(shù)據(jù)之前都必須經(jīng)過字節(jié)序的轉(zhuǎn)換成為網(wǎng)絡(luò)字節(jié)序后再進(jìn)行傳輸。ANSI
C中提供了下面四個(gè)轉(zhuǎn)換字節(jié)序的宏。

當(dāng)前的存儲(chǔ)器,多以byte為訪問的最小單元,當(dāng)一個(gè)邏輯上的整理必須分割為物理
上的若干單元時(shí)就存在了先放誰后放誰的問題,于是endian的問題應(yīng)運(yùn)而生了,對(duì)于不同的存儲(chǔ)方法,就有Big-endian和Little-
endian兩個(gè)描述.(這兩個(gè)術(shù)語來自于 Jonathan Swift
的《《格利佛游記》其中交戰(zhàn)的兩個(gè)派別無法就應(yīng)該從哪一端--小端還是大端--打開一個(gè)半熟的雞蛋達(dá)成一致。在那個(gè)時(shí)代,Swift是在諷刺英國和法國之
間的持續(xù)沖突,Danny
Cohen,一位網(wǎng)絡(luò)協(xié)議的早期開創(chuàng)者,第一次使用這兩個(gè)術(shù)語來指代字節(jié)順序,后來這個(gè)術(shù)語被廣泛接納了。)
存在"如果說"跟word或者說字長根本就沒關(guān)系",假設(shè)有一數(shù)據(jù)文件里面有N多數(shù)順序排布,如果想以Little-Endian
format
讀入內(nèi)存某區(qū)域,那么應(yīng)該怎么讀?怎么排?"這樣的問題是由于對(duì)于endian的實(shí)質(zhì)理解的偏差,endian指的是當(dāng)物理上的最小單元比邏輯上的最小單
元小時(shí),邏輯到物理的單元排布關(guān)系。這里的"有一數(shù)據(jù)文件里面有N多數(shù)順序排布",這個(gè)"有一數(shù)據(jù)"顯然不是邏輯上的最小單元,而其中的"N多數(shù)"的一個(gè)
才是邏輯最小單元,于是可應(yīng)用樓主表格中的原則排列,而"N多數(shù)"之間的順序則是由這"N多數(shù)"的宿主決定的,比如是你寫的程序,這個(gè)順序由你決定.

剛才談到了,endian指的是當(dāng)物理上的最小單元比邏輯上的最小單元小時(shí),邏輯到物理的單元排布關(guān)系。咱們接觸到的物理單元最小都是byte,在通信領(lǐng)域中,這里往往是bit,不過原理也是類似的。

實(shí)踐可以給你更多的經(jīng)驗(yàn),比如在一個(gè)嵌入式系統(tǒng)的通信協(xié)議中,從底層射頻驅(qū)動(dòng)到上層的協(xié)議棧全部需要實(shí)現(xiàn),那么很可能遇到多個(gè)endian的問題,底層的bit序、協(xié)議層的byte序、應(yīng)用層的byte序,這些都是不同的概念.

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多