在計算機中是以字節(jié)為單位,,每個地址對應一個字節(jié),,一個字節(jié)8bit。在C中,,除了8bit的char以外,,還有16bit的short,32位的int,,64位long,,當然具體要由編譯器決定,可以通過sizeof來獲取不同類型在內(nèi)存中占用的字節(jié)數(shù),。在計算機系統(tǒng)中,,當物理單位的長度大于1個字節(jié)時,就要區(qū)分字節(jié)順序,。常見的字節(jié)順序有兩種:Big Endian(High-byte first)和Litter Endian(Low-byte first),,當然還有其他字節(jié)順序,但不常見,,例如Middle Endian,。 一,、最高有效位、最低有效位 要理解Big Endian和Little Endian,,首先要搞清楚MSB和LSB,。 1、MSB(Most Significant Bit)最高有效位 在一個n位二進制數(shù)字中n-1位,,也就是最左邊的位,。 2、LSB(Least Significant Bit)最低有效位 指最右邊的位,。 例如:一個int類型的整型123456789 二進制表達方式:0000 0111 0101 1011 1100 1101 0001 0101(從右向左,,每4bit對齊,最左邊(高位)不夠用0補齊) 十六進制表達方式:0 7 5 B C D 1 5
二,、內(nèi)存地址 在內(nèi)存中,,多字節(jié)對象都是被存儲為連續(xù)的字節(jié)序列。例如在C語言中,,一個類型為int的變量n,,如果其存儲的首個字節(jié)的地址為0x1000,那么剩余3個字節(jié)的地址將存儲在0x1001~0x1003,??傊还芫唧w字節(jié)順序是以什么方式排列,,內(nèi)存地址的分配一般是從小到大的增長,。我們常把0x1000稱為低地址端,把0x1003稱為高地址端,。 三,、大端和小端 搞清楚MSB、LSB,、高位字節(jié),、低位字節(jié),、內(nèi)存地址之后,再理解大端和小端,,就相當容易了,,先看看概念: 小端Little Endian:低字節(jié)存放在低地址,低位字節(jié)排放在內(nèi)存的低地址端,,高位字節(jié)排放在內(nèi)存的高地址端,。 大端Big Endian:高字節(jié)存放在低地址,即高位字節(jié)排放在內(nèi)存的低地址端,,低位字節(jié)排放在內(nèi)存的高地址端,。 以二節(jié)中的例子int類型整數(shù)123456789為例: 小端在內(nèi)存中排列:0x15 0xCD 0x5B 0x07 (低位在前) 大端在內(nèi)存中排列:0x07 0x5B 0xCD 0x15 (高位在前) 從例子中可以看出小端比較符合人的思維,而大端則看上去非常直觀,。 注: 1,、例子中是假設(shè)編譯器支持int為32位的前提下,如果是16位,,那大端的排列則為:0xCD 0x15 0x07 0x5B,。 2、大小端一般是由CPU架構(gòu)決定,,常見的Intel,、AMD的CPU使用的是小端字節(jié)序,而PowerPC使用的是大端字節(jié)序,,有些ARM處理器還可以選擇用大端還是小端模式,,具體請自行查閱。 3,、c#中,,字節(jié)序跟編譯平臺所在的CPU相關(guān),例如在Intel x86 CPU架構(gòu)的windows平臺中,,c#采用的小端序。而Java由于其JVM屏蔽了不同CPU架構(gòu)導致的字節(jié)序差異,,所以默認采用大端字節(jié)序,。所以,大小端模式是由CPU決定,,而編譯器又可能會改變這種模式,。
四,、網(wǎng)絡(luò)字節(jié)序和主機字節(jié)序 網(wǎng)絡(luò)字節(jié)序(Network Order):TCP/IP各層協(xié)議將字節(jié)序定義為Big Endian,因此TCP/IP協(xié)議中使用的字節(jié)序通常稱之為網(wǎng)絡(luò)字節(jié)序,。 主機字節(jié)序(Host Order):整數(shù)在內(nèi)存中保存的順序,,它遵循Little Endian規(guī)則(不一定,,要看主機的CPU架構(gòu))。所以當兩臺主機之間要通過TCP/IP協(xié)議進行通信的時候就需要調(diào)用相應的函數(shù)進行主機序列(Little Endian)和網(wǎng)絡(luò)序(Big Endian)的轉(zhuǎn)換,。
五、C#位操作符 這里簡單記錄一下C#的位操作符,,方便以后自己查閱,,也方便理解后面的講解。 1,、按位與& 1&0為0,;0&0為0;1&1為1,。 2,、按位或| 1|0為1;0|0為0,;1|1為1,。 3、按位取反~ ~1為0,;~0為1,。 4、按位異或^ 1^1為0,;0^0為0,;1^0為1。相等得0,,相異等1,。 5、左移<< 位左移運算,,將整個數(shù)向左移若干位,,左移后空出的部分用0補齊。 6,、右移>> 位右移運算,,將整個數(shù)向右移若干位,右移后空出的部分用0補齊。 六,、C#中關(guān)于大端和小端的轉(zhuǎn)換 using System; namespace Framework.NetPackage.Common { /// <summary> /// 字節(jié)序轉(zhuǎn)換輔助類 /// </summary> public static class Endian { public static short SwapInt16(this short n) { return (short)(((n & 0xff) << 8) | ((n >> 8) & 0xff)); } public static ushort SwapUInt16(this ushort n) { return (ushort)(((n & 0xff) << 8) | ((n >> 8) & 0xff)); } public static int SwapInt32(this int n) { return (int)(((SwapInt16((short)n) & 0xffff) << 0x10) | (SwapInt16((short)(n >> 0x10)) & 0xffff)); } public static uint SwapUInt32(this uint n) { return (uint)(((SwapUInt16((ushort)n) & 0xffff) << 0x10) | (SwapUInt16((ushort)(n >> 0x10)) & 0xffff)); } public static long SwapInt64(this long n) { return (long)(((SwapInt32((int)n) & 0xffffffffL) << 0x20) | (SwapInt32((int)(n >> 0x20)) & 0xffffffffL)); } public static ulong SwapUInt64(this ulong n) { return (ulong)(((SwapUInt32((uint)n) & 0xffffffffL) << 0x20) | (SwapUInt32((uint)(n >> 0x20)) & 0xffffffffL)); } } } 2、BCL庫支持的函數(shù) System.Net.IPAddress.HostToNetworkOrder,、System.Net.IPAddress.NetworkToHostOrder,,這兩個函數(shù)的內(nèi)部實現(xiàn)和上面重復輪子原理一模一樣。 七,、關(guān)于負數(shù) 在計算機中,,負數(shù)以其絕對值的補碼形式表示,不明白可以查閱九中貼出的相關(guān)資源,。關(guān)于負數(shù)的字節(jié)序跟一般整數(shù)的字節(jié)序處理沒有任何區(qū)別,。 八、關(guān)于漢字編碼以及與字節(jié)序的關(guān)系 1,、對于gb2312,、gbk、gb18030,、big5,,其編碼某個漢字產(chǎn)生的字節(jié)順序,由其編碼方案本身決定,,不受CPU字節(jié)序的影響,。其實這幾種編碼的字節(jié)序和大端模式的順序是一致的。
2,、UTF-8 UTF-8和gb系列編碼一樣,,其編碼某個漢字產(chǎn)生的字節(jié)順序,由其編碼方案決定,,不受CPU字節(jié)序的影響,。無論一個漢字有多少個字節(jié),它的字節(jié)序與編碼順序保持一致,。
3,、Unicode Unicode只是一個符號集,,它只規(guī)定了符號的二進制代碼,卻沒有規(guī)定這個二進制代碼應該如何存儲,。所以他沒有要求如何存儲編碼后的字節(jié),,也就受CPU字節(jié)序的影響。 Unicode的具體實現(xiàn)包括UTF-16,、UTF-32(當然也包括UTF-8,,但由于其編碼方式和編碼后的字節(jié)序與其他Unicode編碼實現(xiàn)有較大區(qū)別,所以單獨拿出來講解的),。 4,、總結(jié) 1,、網(wǎng)絡(luò)通訊 在實際的網(wǎng)絡(luò)通訊中,網(wǎng)絡(luò)協(xié)議例如TCP是規(guī)定網(wǎng)絡(luò)字節(jié)序(Network Order)是大端,。而針對漢字具體使用什么編碼,,通訊雙方要么提前約定好,要么就需要在數(shù)據(jù)包中標識好漢字具體使用的編碼,。 如果在網(wǎng)絡(luò)通訊中,,涉及例如UTF16這樣區(qū)分大小端的編碼,,除非按網(wǎng)絡(luò)協(xié)議要求采用大端模式是,,否則也要事先約定好,或者在數(shù)據(jù)包中標識好使用的字節(jié)序模式,。 2,、文件 文件的也會存儲漢字,,當然也要進行編碼。如果采用UTF-16這樣的有字節(jié)序模式區(qū)分的編碼,,編碼規(guī)則要求可以在文件頭部的BOM(Byte Order Mark)來標記,。如果沒有標記,除非事先知道字節(jié)序的模式,,否則只能大小端都試一遍,。
九,、參考資源 http://baike.baidu.com/view/1922338.htm http://www./izualzhy/archive/2011/10/20/158784.html http://www.cnblogs.com/junsky/archive/2009/08/06/1540727.html(負數(shù)的二進制表示方法) http://www.cnblogs.com/augellis/archive/2009/09/29/1576501.html (sizeof) http://www./blog/2007/10/ascii_unicode_and_utf-8.html(漢字編碼) http://djt.qq.com/article/view/658?ADTAG=email.InnerAD.weekly.20130902(漢字編碼) |
|
來自: 郭恩 > 《網(wǎng)絡(luò)編程》