字節序和大小端

<div class="Section0"> <h2>1. 字節順序</h2> <p class="p0"><strong>字節順序(Endian) </strong></p> <p class="p0">字節序是指多字節數據在計算機內存中存儲或者網絡傳輸時各字節的存儲順序。</p> <p class="p0">&#160; 計算機系統通常採用字節<span style="font-family: &#39;Times New Roman&#39;">(Byte</span>(8 bit ))<span style="font-family: 宋體">做爲邏輯尋址單位。當物理單位的長度大於</span><span style="font-family: &#39;Times New Roman&#39;">1</span><span style="font-family: 宋體">個字節時,就要區分字節順序</span><span style="font-family: &#39;Times New Roman&#39;">(Byte Order</span>)<span style="font-family: 宋體">。常見的字節順序有兩種:</span><span style="font-family: &#39;Times New Roman&#39;">Big Endian(High-byte first)</span><span style="font-family: 宋體">和</span><span style="font-family: &#39;Times New Roman&#39;">Little Endian(Low-byte first)</span><span style="font-family: 宋體">。</span><span style="font-family: &#39;Times New Roman&#39;">Intel X86</span><span style="font-family: 宋體">平臺採用</span><span style="font-family: &#39;Times New Roman&#39;">Little Endian</span><span style="font-family: 宋體">,而</span><span style="font-family: &#39;Times New Roman&#39;">PowerPC</span><span style="font-family: 宋體">處理器則採用了</span><span style="font-family: &#39;Times New Roman&#39;">Big Endian</span><span style="font-family: 宋體">。</span>&#160;</p> <p class="p0">&#160; endian<span style="font-family: 宋體">指的是當物理上的最小單元比邏輯上的最小單元小時,邏輯到物理的單元排布關係。我們接觸到的物理單元最小都是</span><span style="font-family: &#39;Times New Roman&#39;">byte</span><span style="font-family: 宋體">,在通訊領域中,這裏每每是</span><span style="font-family: &#39;Times New Roman&#39;">bit</span>。</p> <p class="p0">&#160;</p> <h2>2. 最高有效位、最低有效位</h2> <p class="p0"><strong>最高有效位(MSB: Most Significant Bit)</strong></p> <p class="p0">最高有效位(MSB),是指最左邊的位,是在一個n位二進制數字中的n-1位,這個位有最高的權重(2^(n-1))。第一個或最左邊的位,當這個數字被用通常的方式書寫時。</p> <p class="p0">&#160;</p> <p class="p0"><strong>最低有效位(LSB: Least Significant Bit)</strong></p> <p class="p0">最低有效位(LSB),是指最右邊的位,由於寫較不重要的數字到右邊位置符號的協定。相似於一個十進制整數的最不重要的數字,它是在一個(最右邊)位置的數字。</p> <p class="p0">&#160;</p> <h2>3. <span style="font-family: 黑體">大小端</span></h2> <p class="p0"><strong>小端Little endian<span style="font-family: 宋體">:</span>低字節存放在低地址</strong></p> <p class="p0">低地址存放最低有效位(LSB),既低位字節排放在內存的低地址端,高位字節排放在內存的高地址端。</p> <p class="p0">&#160;</p> <p class="p0"><strong>大端Big endian<span style="font-family: 宋體">:高字節存儲在</span>低地址</strong></p> <p class="p0">低地址存放最高有效位(MSB),既高位字節排放在內存的低地址端,低位字節排放在內存的高地址端。</p> <p class="p0">&#160; </p> <p class="p0"><strong>例子</strong>:好比數字<span style="font-family: &#39;Times New Roman&#39;">0x12345678</span>(雙字、四字節)在兩種節序<span style="font-family: &#39;Times New Roman&#39;">CPU</span><span style="font-family: 宋體">中的存儲順序以下所示:</span></p> <p class="p0">Little Endian&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <br />&#160;&#160;&#160; 低地址 --------------------------------------&gt; 高地址 <br />&#160;&#160;&#160; -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ <br />&#160;&#160; |&#160; 78&#160; | 56&#160; |&#160; 34&#160; |&#160; 12&#160; | <br />&#160;&#160;&#160; -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</p> <p class="p0">Big Endian&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <br />&#160;&#160;&#160; 低地址 --------------------------------------&gt; 高地址 <br />&#160;&#160;&#160; -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ <br />&#160;&#160; | 12&#160; | 34&#160; | 56&#160; | 78&#160; | <br />&#160;&#160;&#160; -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</p> <p class="p0">&#160;</p> 1. 多字節數據纔有大小端序列。單字節(如char)不考慮字節序大小端。</div> <div class="Section0">2. Big Endian判別一個數的正負很容易,只要取低地址的第一個字節就能確認。Little Endian長度爲1,2,4字節的數,排列方式都是同樣的,數據類型轉換很是方便。</div> <div class="Section0">3. little-endian 最符合人的思惟的字節序(地址低位存儲值的低位,地址高位存儲值的高位)。低位值小,就應該放在內存地址小的地方;高位值就應該放在內存地址大的地方。 <br />&#160;&#160; big-endian 最直觀的字節序(地址低位存儲值的高位,地址高位存儲值的低位)只須要把內存地址從左到右按照由低到高的順序寫出 </div> <div class="Section0">&#160;</div> <div class="Section0"><strong>C++判斷主機是大小端</strong></div> <div class="Section0"><strong></strong></div> <div class="Section0">&#160;</div> <pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"><span style="color: #008000">//方法一:</span> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"><span style="color: #008000">//1.原理:多字節類型強制轉換類型成單字節,char單字節指向多字節低地址,便可判斷大小端</span> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"><span style="color: #0000ff">const</span> <span style="color: #0000ff">int</span> endian = 1; </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">#define isBigEndian() ( (*(<span style="color: #0000ff">char</span>*) &amp;endian) == 0 ) <span style="color: #008000">//true大端</span> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">#define IsLittleEndian() ( (*(<span style="color: #0000ff">char</span>*) &amp;endian) == 1 ) <span style="color: #008000">//true小端</span> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"></pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"><span style="color: #008000">//2.原理:將short(2字節)強制類型轉換成char單字節,b指向a的起始字節(低字節)</span> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"><span style="color: #0000ff">void</span> IsBigEndian() </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">{ </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #0000ff">short</span> a = 0x1122; <span style="color: #008000">//十六進制,一個數值佔4位</span> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #0000ff">char</span> b = *(<span style="color: #0000ff">char</span> *)&amp;a; <span style="color: #008000">//經過將short(2字節)強制類型轉換成char單字節,b指向a的起始字節(低字節)</span> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #0000ff">if</span>( b == 0x11) <span style="color: #008000">//低字節存的是數據的高字節數據</span> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> { </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> printf(&quot;<span style="color: #8b0000">大端模式</span>&quot;); <span style="color: #008000">//是大端模式</span> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> } </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #0000ff">else</span> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> { </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> printf(&quot;<span style="color: #8b0000">小端模式</span>&quot;); <span style="color: #008000">//是小端模式</span> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> } </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">} </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"></pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"><span style="color: #008000">//方法二:</span> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"><span style="color: #008000">//原理:聯合體union的存放順序是全部成員都從低地址開始存放,並且全部成員共享存儲空間</span> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"><span style="color: #0000ff">void</span> IsBigEndian() </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">{ </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #0000ff">union</span> temp </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> { </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #0000ff">short</span> <span style="color: #0000ff">int</span> a; </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #0000ff">char</span> b; </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> }temp; </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> temp.a = 0x1234; </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #0000ff">if</span>( temp.b == 0x12 ) <span style="color: #008000">//低字節存的是數據的高字節數據</span> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> { </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> printf(&quot;<span style="color: #8b0000">大端模式</span>&quot;); <span style="color: #008000">//是大端模式</span> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> } </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #0000ff">else</span> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> { </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> printf(&quot;<span style="color: #8b0000">小端模式</span>&quot;); <span style="color: #008000">//是小端模式</span> </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> } </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">} </pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"></pre><pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"></pre></pre>網絡

<div class="Section0"> <h2>4. <span style="font-family: 黑體">網絡字節序、主機序</span></h2>函數

<p class="p0"><strong>網絡字節序(Network Order)</strong></p>spa

<p class="p0">TCP/IP各層協議將字節序定義爲Big-Endian,所以TCP/IP協議中使用的字節序一般稱之爲網絡字節序。</p>.net

<p class="p0">&#160;</p>code

<p class="p0"><strong>主機序(Host Orader)</strong></p>blog

<p class="p0">整數在內存中保存的順序,它遵循Little-Endian規則。因此當兩臺主機之間要經過TCP/IP協議進行通訊的時候就須要調用相應的函數進行主機序(Little-Endian)和網絡序(Big-Endian)的轉換。</p>內存

<p class="p0">&#160;<em id="__mceDel">&#160;</em></p>開發

<p class="p0">1. 在網絡程序開發時 或是跨平臺開發時,要注意通訊雙方協商好字節序。</p>get

<p class="p0">2. 節序轉換的函數: <br />&#160; htons (<span style="font-family: &#39;Times New Roman&#39;">host to network </span>unsigned short) 把<span style="font-family: &#39;Times New Roman&#39;">unsigned short</span><span style="font-family: 宋體">類型從主機序轉換到網絡序</span> it

<br />&#160; htonl (<span style="font-family: &#39;Times New Roman&#39;">host to network </span>unsigned long) 把<span style="font-family: &#39;Times New Roman&#39;">unsigned long</span><span style="font-family: 宋體">類型從主機序轉換到網絡序</span>&#160; <br />&#160; ntohs (<span style="font-family: &#39;Times New Roman&#39;">network to host </span>unsigned short) 把<span style="font-family: &#39;Times New Roman&#39;">unsigned short</span><span style="font-family: 宋體">類型從網絡序轉換到主機序</span> 

<br />&#160; ntohl (<span style="font-family: &#39;Times New Roman&#39;">network to host </span>unsigned long) 把<span style="font-family: &#39;Times New Roman&#39;">unsigned long</span><span style="font-family: 宋體">類型從網絡序轉換到主機序&#160; </span></p>

<p class="p0">&#160;</p>

<p class="p0"><span style="font-family: 宋體"><a href="http://my.oschina.net/alylee/blog/187505" target="_blank">歡迎轉載,轉載請註明出處,謝謝!</a></span></p>

<p class="p0"><span style="font-family: 宋體">&#160;</span></p> </div>

相關文章
相關標籤/搜索