Big-Endian 和 Little-Endian 字節(jié)排序
字節(jié)排序 含義 Big-Endian 一個(gè)Word中的高位的Byte放在內(nèi)存中這個(gè)Word區(qū)域的低地址處。 Little-Endian 一個(gè)Word中的低位的Byte放在內(nèi)存中這個(gè)Word區(qū)域的低地址處。
必須注意的是:表中一個(gè)Word的長(zhǎng)度是16位,一個(gè)Byte的長(zhǎng)度是8位。如果一個(gè)數(shù)超過(guò)一個(gè)Word的長(zhǎng)度,必須先按Word分成若干部分,然后每一部分(即每個(gè)Word內(nèi)部)按Big-Endian或者Little-Endian的不同操作來(lái)處理字節(jié)。
一個(gè)例子: 如果我們將0x1234abcd寫(xiě)入到以0x0000開(kāi)始的內(nèi)存中,則結(jié)果為 big-endian little-endian 0x0000 0x12 0xcd 0x0001 0x34 0xab 0x0002 0xab 0x34 0x0003 0xcd 0x12 Top
5 樓shockwave_115(采姑娘的小蘑菇) 回復(fù)于 2005-06-18 14:06:48 得分 0 怎么寫(xiě)一個(gè)函數(shù)判斷機(jī)器是big_endian還是little_endian?Top
6 樓zhousqy(標(biāo)準(zhǔn)C匪徒)(甩拉,甩拉) 回復(fù)于 2005-06-18 14:33:49 得分 7 #include <stdio.h>
int main(int argc, char **argv) { union { short s; char c[sizeof(short)]; } un;
un.s = 0x0102;
if (sizeof(short) == 2) { if (un.c[0] == 1 && un.c[1] == 2) printf("big-endian\n"); else if (un.c[0] == 2 && un.c[1] == 1) printf("little-endian\n"); else printf("unknown\n"); } else printf("sizeof(short) = %d\n", sizeof(short));
exit(0); } 測(cè)試下面說(shuō)法:我們知道一個(gè)結(jié)構(gòu) 在不同的compiler下其在內(nèi)存中的map是不一樣的。
比如在VC(little Endian) struct TypeA { unsigned long a:1; unsigned long b:1; unsigned long c:3; unsigned long d:3;
unsigned long e:1; unsigned long f:1; unsigned long g:1; unsigned long h:1; unsigned long i:1; unsigned long j:2; unsigned long k:1; unsigned long l:12; unsigned long m:1; unsigned long n:3; }
在Window下(little Endian)其在內(nèi)存中的Map為: n|m|l|k|j|i|h|g|f|e|d|c|b|a
而在MIPS下(Big Endian)其在內(nèi)存中的Map為: a|b|c|d|e|f|g|h|i|j|k|l|m|n;
這些都是編譯器造成的影響;
奇怪的little/big endian問(wèn)題,請(qǐng)大家發(fā)言 樓主mimepp(你好呀) 2005-06-21 12:36:42 在 VC/MFC / ATL/ActiveX/COM 提問(wèn) 進(jìn)來(lái)看帖子的朋友都幫著up一下,讓帖子別沉了.
問(wèn)題描述: 從網(wǎng)絡(luò)上某window XP的PC上收到一串內(nèi)容 buffer, 表示為16進(jìn)制如下: (共11 bytes) 00 b9 0b ,01 00 00 00, 00 04 00 00 -----> 內(nèi)存中看到的內(nèi)容如上,從左往右是內(nèi)存地址增加方向. 現(xiàn)在有個(gè)指針指向 "01" 的位置. 用char *data表示. 這個(gè)data的內(nèi)容是要賦值給一個(gè)結(jié)構(gòu)的. struct test { int a; int b; }; 即 void fun(char *data, int datalen) { struct test *t = (struct test*)data; //data指向"01"所在的地方. printf("result, a: 0x%08x, b: 0x%08x\n", t->a, t->b); printf("result, a: %d, b: %d\n", t->a, t->b); } 傳進(jìn)去的 datalen = 8;
得到的結(jié)果應(yīng)該是 result, a: 0x00000001, b: 0x00000400 result, a: 1, b: 1024
也就是說(shuō),我要得到"01"后面, 每4個(gè)字節(jié)的內(nèi)容到一個(gè)int中.
但實(shí)際運(yùn)行的結(jié)果卻不是如此. 實(shí)際的結(jié)果是: result, a: 0x010bb900, b: 0x00000000 result, a: 17545472, b: 0
即我本來(lái)想得到的數(shù)據(jù)應(yīng)該為"01" 后面的內(nèi)容,但實(shí)際的結(jié)果卻是走到了"01"左邊的幾個(gè)字節(jié)上. b的內(nèi)容也變成了"01" 后面的"00"的那4個(gè)字節(jié).
以上的代碼是運(yùn)行在某ARM開(kāi)發(fā)板上的結(jié)果. 開(kāi)發(fā)板上sizeof(int)是 4 即4個(gè)字節(jié)表示一個(gè)整數(shù). sizeof(struct test)為8 data的指針point為0x09...87, 后面的兩位為87. 中間的沒(méi)記下.
后來(lái)經(jīng)過(guò)改寫(xiě): struct test tmp; memcpy( &tmp, data, sizeof(sturct test)); printf("result, a: 0x%08x, b: 0x%08x\n", tmp->a, tmp->b); printf("result, a: %d, b: %d\n", tmp->a, tmp->b); 使用memcpy 來(lái)復(fù)制內(nèi)存內(nèi)容后,結(jié)果輸出正確. memcpy應(yīng)該是把data右邊的內(nèi)容copy正確到了tmp中.問(wèn)題最后是解決了的.
疑問(wèn): 1. 有人說(shuō)不是little/big endian的問(wèn)題,是數(shù)據(jù)結(jié)構(gòu)struct test對(duì)齊的問(wèn)題. 大家什么意見(jiàn)? 說(shuō)是從"data的指針point為0x09...87, 后面的兩位為87." 看出的問(wèn)題. 不被4整除? 好像不是這樣吧.大家聊聊自己的看法. 2. 錯(cuò)誤出現(xiàn)時(shí), 取到的結(jié)果是 a: 01 0b b9 00 b: 00 00 00 00 也就是在字串被這樣處理了 00 b9 0b 01, 00 00 00 00, 04 00 00 即data指向的"01"被當(dāng)成了高位.低位在它的左邊. 即得到的是"01"加上它左邊的3個(gè)字符,而不是右邊的3個(gè)字符. 不知是否這樣解釋? 但這個(gè)解釋好像很奇怪喔. 怎么跑到了左邊?
3. 一般大家討論的情況可能只會(huì)涉及到 01 00 00 00, 00 04 00 00 這個(gè)的排列的內(nèi)容的含義: 如: 一種排列為: 01 00 00 00 00 04 00 00 另一種排列為: 00 00 00 01 00 00 04 00
但我這里遇到的是實(shí)際運(yùn)行系統(tǒng)中的現(xiàn)象. 和這個(gè)討論有點(diǎn)不同. 請(qǐng)大家就我的實(shí)際例子來(lái)討論. 4. 難道是內(nèi)存中數(shù)據(jù)被其他的代碼"踩到", 出錯(cuò)了? 5. 不知道代碼中其他地方還有沒(méi)有這樣的后患.呵呵.
相關(guān)知識(shí),來(lái)自網(wǎng)絡(luò): 1. Big-Endian 和 Little-Endian 翻譯為: 大端,小端 2. Big-Endian 和 Little-Endian 這兩個(gè)術(shù)語(yǔ)來(lái)自于 Jonathan Swift 的《《格利佛游記》其中交戰(zhàn)的兩個(gè)派別無(wú)法就應(yīng)該從哪一端--小端還是大端--打開(kāi)一個(gè)半熟的雞蛋達(dá)成一致。:) 在那個(gè)時(shí)代,Swift是在諷刺英國(guó)和法國(guó)之間的持續(xù)沖突,Danny Cohen,一位網(wǎng)絡(luò)協(xié)議的早期開(kāi)創(chuàng)者,第一次使用這兩個(gè)術(shù)語(yǔ)來(lái)指代字節(jié)順序,后來(lái)這個(gè)術(shù)語(yǔ)被廣泛接納了 摘自《深入理解計(jì)算機(jī)系統(tǒng)》 3. 含義: big endian:最高字節(jié)在地址最低位,最低字節(jié)在地址最高位,依次排列。 little endian:最低字節(jié)在最低位,最高字節(jié)在最高位,反序排列。 沒(méi)記錯(cuò)的話,除了moto的68K系列和dec的sparc是big endian外,常見(jiàn)的cpu都是little endian。ARM同時(shí)支持big和little,實(shí)際應(yīng)用中通常使用little endian。
歡迎大家討論. http://cache.baidu.com/c?word=struct%2Cendian&url=http%3A//topic%2Ecsdn%2Enet/t/20050621/12/4096371%2Ehtml&p=cb759a42dd9812a059ed8535540894&user=baidu
一個(gè)微軟面試題--關(guān)于位結(jié)構(gòu)體
2007-09-23 08:49:23 大中小 標(biāo)簽:學(xué)習(xí)公社 備案待查,指不定啥時(shí)候就用上了。 寫(xiě)出下列程序在X86上的運(yùn)行結(jié)果。 struct mybitfields { unsigned short a : 4; unsigned short b : 5; unsigned short c : 7; }test;
void main(void) { int i; test.a=2; test.b=3; test.c=0; i=*((short *)&test); printf("%d ",i); } 這
個(gè)題的為難之處呢,就在于前面定義結(jié)構(gòu)體里面用到的冒號(hào),如果你能理解這個(gè)符號(hào)的含義,那么問(wèn)題就很好解決了。這里的冒號(hào)相當(dāng)于分配幾位空間,也即在定義
結(jié)構(gòu)體的時(shí)候,分配的成員a 4位的空間, b 5位,c 7位,一共是16位,正好兩個(gè)字節(jié)。下面畫(huà)一個(gè)簡(jiǎn)單的示意: 變量名 位數(shù) test 15 14 13 12 11 10 9 |8 7 6 5 4 |3 2 1 0 test.a | |0 0 1 0 test.b |0 0 0 1 1 | test.c 0 0 0 0 0 0 0 | | 在
執(zhí)行i=*((short *)&test);
時(shí),取從地址&test開(kāi)始兩個(gè)字節(jié)(short占兩個(gè)字節(jié))的內(nèi)容轉(zhuǎn)化為short型數(shù)據(jù),即為0x0032,再轉(zhuǎn)為int型為
0x00000032,即50。輸出的結(jié)果就是50。當(dāng)然,這里還涉及到字節(jié)及位的存儲(chǔ)順序問(wèn)題,后面再說(shuō)。 前面定義的結(jié)構(gòu)體被稱為位結(jié)構(gòu)體。所謂位結(jié)構(gòu)體,是一種特殊的結(jié)構(gòu)體,在需要按位訪問(wèn)字節(jié)或字的一個(gè)或多個(gè)位時(shí),位結(jié)構(gòu)體比按位操作要更方便一些。 位結(jié)構(gòu)體的定義方式如下: struct [位結(jié)構(gòu)體名]{ 數(shù)據(jù)類型 變量名:整數(shù)常數(shù); ... }位結(jié)構(gòu)變量; 說(shuō)明: 1)這里的數(shù)據(jù)類型只能為int型(包括signed和unsigned); 2)整數(shù)常數(shù)必須為0~15之間的整數(shù),當(dāng)該常數(shù)為1時(shí),數(shù)據(jù)類型為unsigned(顯然嘛,只有一位,咋表示signed?光一符號(hào)?沒(méi)意義呀); 3)按數(shù)據(jù)類型變量名:整數(shù)常數(shù);方式定義的結(jié)構(gòu)成員稱為位結(jié)構(gòu)成員,好像也叫位域,在一個(gè)位結(jié)構(gòu)體中,可以同時(shí)包含位結(jié)構(gòu)成員及普通的結(jié)構(gòu)成員; 4)位結(jié)構(gòu)成員不能是指針或數(shù)據(jù),但結(jié)構(gòu)變量可以是指針或數(shù)據(jù); 5)位結(jié)構(gòu)體所占用的位數(shù)由各個(gè)位結(jié)構(gòu)成員的位數(shù)總各決定。如在前面定義的結(jié)構(gòu)體中,一共占用4+5+7=16位,兩個(gè)字節(jié)。另外我們看到,在定義位結(jié)構(gòu)成員時(shí),必須指定數(shù)據(jù)類型,這個(gè)數(shù)據(jù)類型在位結(jié)構(gòu)體占用多少內(nèi)存時(shí)也起到不少的作用。舉個(gè)例子: struct mybitfieldA{ char a:4; char b:3; }testA; struct mybitfieldB{ short a:4; short b:3; }testB; 這
里,testA占用一個(gè)字節(jié),而testB占用兩個(gè)字節(jié)。知道原因了吧。在testA中,是以char來(lái)定義位域的,char是一個(gè)字節(jié)的,因此,位域占
用的單位也按字節(jié)做單位,也即,如果不滿一個(gè)字節(jié)的話按一個(gè)字節(jié)算(未定義的位按零處理)。而在testB中,short為兩個(gè)字節(jié),所以了,不滿兩個(gè)字
節(jié)的都按兩個(gè)字節(jié)算(未定義位按零處理) 關(guān)于位結(jié)構(gòu)體在內(nèi)存中的存儲(chǔ)問(wèn)題 Kevin‘s Theory #2: In a C
structure that contains bit fields, if field A is defined in front of
field B, then field A always occupies a lower bit address than field B.
(來(lái)自http://www./forum/showflat.php?Cat=&Board=linuxk&Number=638637&page=0&view=collapsed&sb=5&o=all&fpart=all) 說(shuō)的是,在C結(jié)構(gòu)體中,如果一個(gè)位域A在另一個(gè)位域B之前定義,那么位域A將存儲(chǔ)在比B小的位地址中。 如果一個(gè)位域有多個(gè)位時(shí),各個(gè)位的排列順序通常是按CPU的端模式(Endianess)來(lái)進(jìn)行的,即在大端模式(big endian)下,高有效位在低位地址,小端模式則相反。 補(bǔ)充說(shuō)明一個(gè)關(guān)于位域與普通結(jié)構(gòu)成員一起使用的問(wèn)題 先看一個(gè)例子 struct mybitfield{ char a:4; char b:3; char aa; char c:1;}test; 這種情況下,test應(yīng)該占幾個(gè)字節(jié)呢?2個(gè)(4+3+1=8占一個(gè)字節(jié),aa占一個(gè))還是3個(gè)(4+3不足補(bǔ)一位,占一個(gè)字節(jié),aa占一個(gè)字節(jié),c占一個(gè)字節(jié))? 寫(xiě)個(gè)小程序驗(yàn)證一下: int main(int argc, char* argv[]) { int i; test.a = 1; test.b = 1; test.aa = 1; test.c = 1;
i=*((short *)&test); printf("%d \n",i);
return 0; }
|