部分1:大端小端概念
摘自:計算機系統中記憶體是以位元組為單位進行編址的,每個位址單元都唯一的對應著1個位元組(8 bit)。這可以應對char型別資料的儲存要求,因為char型別長度剛好是1個位元組,但是有些型別的長度是超過1個位元組的(字串雖然是多位元組的,但它本質是由乙個個char型別組成的類似陣列的結構而已),比如c/c++中,short型別一般是2個位元組,int型別一般4個位元組等。因此這裡就存在著乙個如何安排多個位元組資料中各位元組存放順序的問題。正是因為不同的安排順序導致了大端儲存模式和小端儲存模式的存在。
1. 概述
記憶體位址 0x4000 8000(低位址) 0x4000 8001 0x4000 8002 0x4000 8003(高位址)
大端模式 0x12(高位元組) 0x34 0x56 0x78(低位元組)
小端模式 0x78(低位元組) 0x56 0x34 0x12(高位元組)
明顯可以看出規律,即大端「高低低高」,小端「高高低低」:
說明:0x代表16進製制,由於16為2的4次方,剛好可以用4位半個位元組表示;,或者說兩個16進製制數用乙個位元組表示。所以對於16進製制的儲存可以說:乙個16進製制數佔4位,或者說兩個16進製制數佔乙個位元組。比如對於int 0x12345678,0x12、0x34、0x56、0x78各佔乙個位元組,直接翻譯二進位制為0001、0010,0011、0100,0101、0110,0111、1111;這種翻譯方法與將0x12345678先轉為10進製,再換算為二進位制結果一致。
1.2 特點
為什麼截然相反的大小端儲存模式能夠並存至今?在標準化備受推崇的今天,為什麼大小端誰都沒有被另外乙個所同化?我想這除了歷史的慣性使然,還與它們各自的優缺點有關。
大端模式優點:符號位在所表示的資料的記憶體的第乙個位元組中,便於快速判斷資料的正負和大小
小端模式優點:1. 記憶體的低位址處存放低位元組,所以在強制轉換資料時不需要調整位元組的內容(註解:比如把int的4位元組強制轉換成short的2位元組時,就直接把int資料儲存的前兩個位元組給short就行,因為其前兩個位元組剛好就是最低的兩個位元組,符合轉換邏輯); 2. cpu做數值運算時從記憶體中依順序依次從低位到高位取資料進行運算,直到最後重新整理最高位的符號位,這樣的運算方式會更高效
其各自的優點就是對方的缺點,正因為兩者彼此不分伯仲,再加上一些硬體廠商的堅持(見1.3節),因此在多位元組儲存順序上始終沒有乙個統一的標準
1.3 現狀
intel的80×86系列晶元使用小端儲存模式
arm晶元預設採用小端,但可以切換為大端
mips晶元採用大端,但可以在大小端之間切換
在網路上傳輸的資料普遍採用的都是大端
2. 判斷
方法一:通過將多位元組資料強制型別轉換成單位元組資料,再通過判斷起始儲存位置是資料高位元組還是低位元組進行檢測
// @ret: 大端,返回true; 小端,返回false
bool isbigendian_1()
方法二:利用聯合體union的存放順序是所有成員都從低位址開始存放這一特性進行檢測
// @ret: 大端,返回true; 小端,返回false
bool isbigendian_2()
;uendian u;
u.nnum = 0x12345678;
if ( u.clowaddressvalue == 0x12 ) return true;
return false;
}3. 轉換
3.1 大小端轉換
// 實現16bit的資料之間的大小端轉換
#define blswitch16(a) ( ( ( (uint16)(a) & 0xff00 ) >> 8 ) | \
( ( (uint16)(a) & 0x00ff ) << 8 ) )
// 實現32bit的資料之間的大小端轉換
#define blswitch32(a) ( ( ( (uint32)(a) & 0xff000000) >> 24) |\
(((uint32)(a) & 0x00ff0000) >> 8) | \
(((unit32)(a) & 0x0000ff00) << 8) | \
(((uint32)(a) & 0x000000ff) << 32) )
3.2 網路位元組序與主機位元組序的轉換
方法三:使用記憶體檢視器
**:檢視記憶體是使用vs2010進行編碼的乙個非常基本的技能了,快速而準確地檢視記憶體,可以幫助你準確分析**中各變數的取值,以及儲存狀態,幫助你發現程式中的bug,改進**的健壯性。
如何檢視記憶體?繼續採用以上的例程進行說明,將程式f5到第13行,再單步到下一句
圖3按下alt+6,此時我們可以看到記憶體1的視窗,我們從自動視窗中先找到指標p的位址,然後將位址複製到記憶體位址列中,回車,即可看到此時位址中的值。記憶體視窗中左邊的灰色值代表位址,右邊則表示位址中儲存的值。我們可以看到p位址對應的值為03,但後面還有000000跟著,其實因為我們儲存的是乙個整數值,需要4個位元組儲存,因此就算p中結果是3,也同樣占用了4個位元組。
這裡還需要注意的乙個概念是,大端法儲存和小端法儲存的概念。回到上面圖中我們可以看出,記憶體位址從左至右,從上至下是依次增大的。我們這個值3其實正確的讀法應該是從右至左讀取的,即0x00000003,03是在最低位,而03也是儲存在記憶體位址中的低位址中的,因此這是小端法儲存,大端法則剛好相反。需要了解這方面更多資訊的人,一定要上網查詢更多資料多學習,本文就不再詳述。
部分2:數字儲存與大端小端結合
例題1union aunion
val;
int main()
輸出的值是多少?
5的二進位制為0000 0101,1二進位制為0000 0001,所以排列順序為0000 0101 0000 0001,(記憶體中:位址由小到大,並且每個位址單元都唯一的對應著1個位元組(8 bit))。若為小端,則val.k在取出時,5、1的二進位制被解釋為0000 0001 0000 0101,其10進製數為261;若為大端,則val.k在取出時,5、1被解釋為0000 0101 0000 0001,位2861。
例題2int main()
求輸出到螢幕的數
首先明確整數的儲存方式:正整數直接儲存其二進位制形式,位數不夠時,在其二進位制數左邊補0;對於負整數,先求出其正數的二進位制,然後對此二進位制數求補碼即可。
所以對於-1計算方法為:
1的二進位制 :0000 0001
對上述求補碼:1111 1111
所以字元a、b都是儲存的1111 1111,由於a是有符號的char,故取1111 1111補碼,為0000 0001,輸出1;b是無符號的char,故輸出為1111 1111對應的數字255。
float、double的儲存方式:先將該數轉為對應的二進位制,在寫成二進位制對應的科學計數法,之後儲存該數的三部分資訊,分別是符號、指數、尾數(小數點後邊的數,小數點前邊的數必為1);
符號正為0,負為1,指數採用餘碼方式(使得沒有指數部分沒有複數)float為餘127碼(指數加上127),double為餘1023碼(指數加上11023),尾數部分可以看成是正整數的儲存方式;
二進位制讀寫之大端VS小端
所謂大端 big endian 小端 little endian 是指計算機在讀寫資料時遵循的位元組排列順序,即位元組序 byte order 想要理解位元組序,必須得先了解位元組。計算機cpu執行任何程式,處理任何事物,都是在執行一段由0 1組成的二進位制機器指令 也就說計算機只認識0和1 每個0...
二進位製小技巧
二進位制嘛,可以加速 a 2 a 1 a 2 a 1 2 b 1 b 可以判斷一些東西 a 1 a 2 1 a 1可以求出數的乙個相鄰數 等等等等 下面我會在做題目時記錄一下位運算的技巧 這題讓我們統計區間顏色種類,種類不超過30種 那我們可以用位運算來壓縮 開乙個int,轉換成二進位制後可以清晰的...
二進位製小技巧
目錄 xx 1 xx1xx1 x x現在令 x 10101000,接下來我們算一下 x x 1 的結果。首先我們回憶一下二進位制減法的規則 0 0 1 1 0 1 0 1 0 1 1 向高位借位 例如,11000011 2 00101101 2的算式如下 11000011 被減數 00101101 ...