字节序

我们将一个4字节的汉字存入一段4字节的物理容器里, 该怎么存放? 直觉都是从左往右依次写入, 但也可以从右向左写, 甚至可以先写入奇字节再写偶字节, 这样比划下可以有n!种存储方式(n是字节数), 反正只要保证写入和读出的数据一致即可.

这就引入了字节序的问题.

谈到字节序的问题,必然牵涉到两大CPU派系。那就是IBM的PowerPC系列CPU和Intel的x86系列CPU。PowerPC系列采用big endian方式存储数据,而x86系列则采用little endian方式存储数据。

那么究竟什么是big endian,什么又是little endian呢?

big endian是指低地址存放最高有效字节(MSB),而little endian则是低地址存放最低有效字节(LSB)。

用文字说明可能比较抽象,下面用二维文字加以说明。比如数字0x12345678在两种不同字节序CPU中的存储顺序如下所示:

Big Endian:

低地址                                            高地址

----------------------------------------->

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

|     12     |      34    |     56      |     78    |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Little Endian:

低地址                                            高地址

----------------------------------------->

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

|     78     |      56    |     34      |     12    |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

从上面两图可以看出,采用big endian方式存储数据是符合我们人类的思维习惯的。而little endian,!@#$%^&*,见鬼去吧 -_-|||

喜欢思考的同学应该想到, 字节序不止big和little endian这2种, 根据排列组合, 总共有n!种(n是字节数), 只是这2种最直接.

为什么要注意字节序的问题呢?你可能这么问。当然,如果你写的程序只在单机环境下面运行,并且不和别人的程序打交道,那么你完全可以忽略字节序的存在。但是,如果你的程序要跟别人的程序产生交互呢?

C/C++里数据存储顺序是跟编译平台所在的CPU相关的,而JAVA编写的程序则唯一采用big endian方式来存储。试想,如果你用C/C++语言在x86平台下编写的程序跟别人的JAVA程序互通时会产生什么结果?就拿上面的0x12345678来说,你的程序将指向0x12345678的指针传给了JAVA程序,由于JAVA采取big endian方式存储数据,很自然的它会将你的数据翻译为0x78563412。什么?竟然变成另外一个数字了?是的,就是这种后果。因此,C程序传给JAVA程序之前有必要进行字节序的转换工作。

用通俗的话描述上述的过程就是:

C++: 我这有一段4byte的数据给你用, 内存地址范围是0x1000到0x1003, 使用愉快:-)

Java: 好嘞. 心想: 嗯...这4个字节找到了, 既然你没说那我就从左到右读取吧.

程序员: 得, 完蛋!

网络传输的顺序

无独有偶,所有网络协议也都是采用big endian的方式来传输数据的。所以有时我们也会把big endian方式称之为网络字节序。

当传输大文件时候, 比如视频这种可以"边下边播"的内容时, big endian就非常重要了. 当然如果是加密后分段传输的数据就无所谓.

当两台采用不同字节序的主机通信时,在发送数据之前都必须经过字节序的转换成为网络字节序后再进行传输。ANSI C中提供了下面四个转换字节序的宏。

big endian:最高字节在地址最低位,最低字节在地址最高位,依次排列。

little endian:最低字节在最低位,最高字节在最高位,反序排列。

endian指的是当物理上的最小单元比逻辑上的最小单元小时,逻辑到物理的单元排布关系。咱们接触到的物理单元最小都是byte,在通信领域中,这里往往是bit,不过原理也是类似的。

目前应该little endian是主流,因为在数据类型转换的时候(尤其是指针转换)不用考虑地址问题。

Big Endian 和 Little Endian名词的由来

这两个古怪的名称来自英国作家斯威夫特的《格列佛游记》。在该书中,小人国里爆发了内战,战争起因是人们争论,吃鸡蛋时究竟是从大头(Big-endian)敲开还是从小头(Little-endian)敲开。为了这件事情,前后爆发了六次战争,一个皇帝送了命,另一个皇帝丢了王位。

我们一般将big endian和little endian称作“大尾”和“小尾”。

在那个时代,Swift是在讽刺英国和法国之间的持续冲突,Danny Cohen,一位网络协议的早期开创者,第一次使用这两个术语来指代字节顺序,后来这个术语被广泛接纳了

Big Endian 和 Little Endian优劣

Big Endian

判别一个数的正负很容易,只要取offset0处的一个字节就能确认。

Little Endian

长度为1,2,4字节的数,排列方式都是一样的,数据类型转换非常方便。

以上是其他人说的, 其实我觉得吧, 谈优劣根本毫无意义...

一些常见文件的字节序

  • Adobe Photoshop -- Big Endian

  • BMP (Windows and OS/2 Bitmaps) -- Little Endian

  • DXF (AutoCad) -- Variable

  • GIF -- Little Endian

  • IMG (GEM Raster) -- Big Endian

  • JPEG -- Big Endian

  • FLI (Autodesk Animator) -- Little Endian

  • MacPaint -- Big Endian

  • PCX (PC Paintbrush) -- Little Endian

  • PostScript -- Not Applicable (text!)

  • Microsoft RIFF (.WAV & .AVI) -- Both

  • Microsoft RTF (Rich Text Format) -- Little Endian

  • SGI (Silicon Graphics) -- Big Endian

  • Sun Raster -- Big Endian

  • TGA (Targa) -- Little Endian

  • TIFF -- Both, Endian identifier encoded into file

  • BSON -- Little Endian

比特序

可是有朋友仍然会问,CPU存储一个字节的数据时其字节内的8个比特之间的顺序是否也有big endian和little endian之分?或者说是否有比特序的不同?

实际上,这个比特序是同样存在的。下面以数字0xB4(10110100)加以说明。

Big Endian

msb                                                         lsb

---------------------------------------------->

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

|   1  |   0  |   1  |   1  |   0  |   1  |   0  |   0  |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Little Endian

lsb                                                         msb

---------------------------------------------->

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

|   0  |   0  |   1  |   0  |   1  |   1  |   0  |   1  |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

实际上,由于CPU存储数据操作的最小单位是一个字节,其内部的比特序是什么样对我们的程序来说是一个黑盒子。也就是说,你给我一个指向0xB4这个数的指针,对于big endian方式的CPU来说,它是从左往右依次读取这个数的8个比特;而对于little endian方式的CPU来说,则正好相反,是从右往左依次读取这个数的8个比特。而我们的程序通过这个指针访问后得到的数就是0xB4,字节内部的比特序对于程序来说是不可见的,其实这点对于单机上的字节序来说也是一样的。

那可能有人又会问,如果是网络传输呢?会不会出问题?是不是也要通过什么函数转换一下比特序?嗯,这个问题提得很好。假设little endian方式的CPU要传给big endian方式CPU一个字节的话,其本身在传输之前会在本地就读出这个8比特的数,然后再按照网络字节序的顺序来传输这8个比特,这样的话到了接收端不会出现任何问题。

其实网络传输的字节序也好, 比特序也好, 都由网络协议来定义, 比如二进制的http/2, 还有bson, 他们的每一个字段之前有记录着字段长度,至于字段的序, 像bson采用的就是little endian.

一维信息存在的条件: 顺序性

头脑风暴: 字节序问题的根源在哪里?

任何信息都可以用一个数值来表示, 无论多少进制, 信息的每一个位必须从左向右依次排列才有意义. 比如一个数0x1234如果把其中2个字节位置调换就变成了0x3412: 这样信息就失效了.

好, 由于计算机处理数据最小单位是1个8位的字节, 可以想象任何数据都是一个2^8=256进制的数值, 一个n字节的数据就是一个n位256进制数.

描述一段n=3的信息的地址就需要依次给出从左到右每个字节的地址, 也就是这个256进制数的"百位", "十位", "个位". 假如这3个字节的内存地址分别是0,3和2, 那这个数据的地址可以用一个数组表示: [0,3,2], 但是通常数据在存储空间里是连续的, 比如是[5,6,7], 这时候可以通过另一种写法节省空间:{start: 5, end: 8}, 或者{start:5, length:3}. 这样子存储地址的成本从原来的n个降低成2个.

当然, 理论上如果让所有的数据等长, 地址成本就是1个, 不过这个不现实.

之所以上面的地址成本可以降低至2个, 是因为默认了字节顺序是从左至右(big endian), 而且中间没有断点. 当然这个默认顺序也可以是little endian, 甚至是其他的序, 由此引发了本篇文章的核心问题.

顺序问题一直以默认的方式存在, 比如文本的排列总是默认从左到右, 因为字符串中每个字符的信息只表示自己是哪个字符, 并没有透露自己和其他字符之间的位置关系, 所以文本渲染引擎都是从左向右渲染的, 当然也有RTL(right 2 left)的存在, RTL就像little endian一样不可理喻, 哦, RTL至少是UI层面的, 还有一定的存在意义, little endian就........

什么玩意?

字节序: 一个不是很重要的概念相关推荐

  1. 网络字节序与主机字节序的相互转换

    1.网络字节序与主机字节序 在Linux网络编程中,经常碰到网络字节序与主机字节序的相互转换.说到网络字节序与主机字节序需要清晰了解以下几个概念. 字节序,顾名思义,指字节在内存中存储的顺序.比如一个 ...

  2. 网络通信时字节序转换原理与网络字节序、大端和小端模式 .

    引言:在进行网络通信时是否需要进行字节序转换? 相同字节序的平台在进行网络通信时可以不进行字节序转换,但是跨平台进行网络数据通信时必须进行字节序转换.原因如下:网络协议规定接收到得第一个字节是高字节, ...

  3. 网络基础1--计算机网络背景-局广城网范围,还有其他各种网,交换机路由器概念,ip地址,mac端口了解,网络协议,五层模型,传输中数据封装和分用,网络字节序,主机字节序如何判断。

    ** 计算机网络背景 ** 网络发展史:一个网络由路由器星形发散 局域网 1.指覆盖范围在1000米以内的网络 2.计算机的数量较多,通过交换机和路由器连在一起,也被称为服务器. 城域网: 1.指覆盖 ...

  4. 如何仅用递归函数和栈操作逆序一个栈——你要先用stack实现,再去改成递归——需要对递归理解很深刻才能写出来...

    /**  * 如何仅用递归函数和栈操作逆序一个栈  * 题目:  * 一个栈依次压入1,2,3,4,5,那么从栈顶到栈底分别为5,4,3,2,1.  * 将这个栈转置后,从栈顶到栈底为1,2,3,4, ...

  5. 位序、字节序、类型序

    计算机学科中的很多问题,都是因为概念的抽象模糊,导致理解上的不确定性,增加学习领悟的难度.对于计算机中数据存放次序的问题,很多教材或文章要么含糊其辞,要么凭空飞来结论,让人看的一头雾水.几经周折,结合 ...

  6. python16进制字节序_第 1 章 套接字、IPv4和简单的客户端/服务器编程

    第 1 章 套接字.IPv4和简单的客户端/服务器编程 本章攻略: 打印设备名和IPv4地址 获取远程设备的IP地址 将IPv4地址转换成不同的格式 通过指定的端口和协议找到服务名 主机字节序和网络字 ...

  7. (转)挺好的一篇介绍字节序的文章

    转自:http://www.cnblogs.com/JeffreyZhao/archive/2010/02/10/byte-order-and-related-library.html 说到程序间的通 ...

  8. java 大端字节序_理解字节序 大端字节序和小端字节序

    以下内容参考了 http://www.ruanyifeng.com/blog/2016/11/byte-order.html https://blog.csdn.net/yishengzhiai005 ...

  9. linux分析字节序的分类及特点,计算机中的字节序详解 分类: 【Linux/Windows操作系统】 2015-01-07 21:54 97人阅读 评论(0) 收藏...

    我们都知道,内存中存储的是各种变量,各种奇葩东西,不用的变量占用不用的字长,例如在intel X86环境下,一个int占用两个字 0 1 2 3 4 5 6 7 8 9 0x30 0x31 0x32 ...

最新文章

  1. 读书笔记——javascript闭包
  2. linux 更新yum源 改成阿里云源
  3. 傅里叶变换表_Numpy库小抄表!主要语法和代码都在这里啦
  4. 震撼世界的基建狂魔,中国制造的超级工程到底有多牛?
  5. win10控制视频声音大小
  6. Ubuntu下安装LAMP及phpmyadmin
  7. c++中assert
  8. Python——批量发送邮件(持续更新)
  9. CRM系统与呼叫中心系统对接
  10. 分享 25 个有用的 JS 单行代码
  11. 大数据背景下网络舆情监督机制的研究(非原创)
  12. Java实现坦克大战小游戏(源码+注释)
  13. 现代女性的半糖主义ZT
  14. Mat类型中的CV_8UC3、CV_32FC3以及对应的迭代器模板参数Vec3b,Vec3f的一点自己的理解
  15. 计算机考研中的编号,考研科目前边的编号是什么意思
  16. 企业资源计划-MPS计算(附详细解题步骤及计算过程)
  17. JS返回到上一页的三种方法
  18. Aspose for Java 去除水印和数量限制
  19. linux 重启nginx命令
  20. 为什么使用双亲委派机制以及如何破坏双亲委派

热门文章

  1. Ae 表达式语言引用​:Global
  2. 资产管理软件使用方法
  3. latex如何取消自动编号_LaTeX入门(十)——编号二三事
  4. 时间序列预测(1)-什么是时间序列预测
  5. 形态学操作+实例分析(第六天)
  6. android点击右上角图标调转,Android 图标右上角添加数字提醒
  7. SaaSBase:什么是Oracle Fusion ERP?
  8. 毛剑:Bilibili 的 Go 服务实践(上篇)
  9. 从云监工到云登顶,5G云直播见证中国速度
  10. xp如何修改时间服务器,WinXP系统解决时间总是不准确操作步骤