字节序和大小端

心已入冬 提交于 2019-12-06 19:32:19

<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>

<p class="p0">TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。</p>

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

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

<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>

<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>

<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>

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!