前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >字节序: 一个不是很重要的概念

字节序: 一个不是很重要的概念

作者头像
Jean
发布2019-07-30 18:52:07
1.5K0
发布2019-07-30 18:52:07
举报
文章被收录于专栏:Web行业观察Web行业观察

字节序

我们将一个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就........

什么玩意?

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-07-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 WebHub 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档