字节序

我们将一个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. tcpdump抓包并保存到远程服务器
  2. poj1422(最小路径覆盖问题)
  3. bayer格式插值算法实现
  4. python上下文管理器with
  5. 在批处理中运行.sql文件
  6. pythonChallenge:第1关
  7. 作为一名产品经理,我是如何快速做项目计划的?
  8. Java-String的常用方法总结!
  9. becon帧 wifi_WireShark对于WIFI数据帧的分析
  10. JEESZ分布式架构3--CentOs下安装MySQL(环境准备)
  11. 【HAOI2008】【BZOJ1045】糖果传递(环形纸牌均分,前缀和)
  12. 大数据分析平台具备什么功能特点
  13. Windows安装CUDAcuDNNanaconda
  14. Unity 2D角色复活点与复活等待时间设置
  15. NULL 与 nullptr区别与联系
  16. webstorm破解版
  17. HTML鼠标悬停的语法
  18. 结构仿真实验,Midas多跨超静定连续梁手算电算分析
  19. 飞鸽传书——空号检测
  20. caputo分数阶导数程序_caputo分数阶导数

热门文章

  1. 大数据之路——数据同步
  2. 一无所有会如何创业?
  3. 内置式永磁电机maxwell2d_高性能永磁电机设计和制造之ANSYS Maxwell 2D求解齿槽转矩的几种方法...
  4. 面试被问到“你有什么缺点?”这么回答的都拿到Offer了!
  5. Wikibon:英伟达如何通过人工智能抢夺数据中心市场?
  6. 我的页面我做主——浏览器去广告正确姿势
  7. docx poi 原理,如何从Apache POI知道文件是.docx还是.doc格式
  8. 电脑不小心结束桌面进程电脑空白问题解决方案
  9. 英文之妙语连珠(五)(ZT)
  10. JAVA毕业设计专家系统房产营销智能推荐系统计算机源码+lw文档+系统+调试部署+数据库