[TOC] > [参考](https://www.ruanyifeng.com/blog/2016/11/byte-order.html) ## 导读 ### 二进制协议 基于文本类型的协议(比如 JSON)和二进制协议都是字节通信,他们不同点在于他们使用哪种类型的字节和如何组织这些字节。 文本协议只适用于 ASCII 或 Unicode 编码可打印的字符通信。例如 "26" 使用 "2" 和 "6" 的 utf 编码的字符串表示,这种方式方便我们读,但对于计算机效率较低。 在二进制协议中,同样数字 "26" 可使用一个字节**0x1A**十六进制表示,减少了一半的存储空间且原始的字节格式能够被计算机直接识别而不需解析。当一个数字足够大的时候,性能优势就会明显体现 ## 小端序在计算机中优势 使用小端序时不移动字节就能改变 number 占内存的大小而不需内存地址起始位。比如我想把四字节的 int32 类型的整型转变为八字节的 int64 整型,只需在小端序末端加零即可。 ``` 44 33 22 11 44 33 22 11 00 00 00 00 ``` 上述扩展或缩小整型变量操作在编译器层面非常有用,但在网络协议层非也 ### 描述 数值`0x2211`使用两个字节储存:高位字节是`0x22`,低位字节是`0x11`,**并不是数值的大小** >**大端字节序**:高位字节在前,低位字节在后,这是人类读写数值的方法。 >**小端字节序**:低位字节在前,高位字节在后,即以`0x1122`形式储存。 **"只有读取的时候,才必须区分字节序,其他情况都不用考虑。"** ## 为什么会有小端字节序 计算机电路先处理低位字节,效率比较高,因为计算都是从低位开始的。所以,计算机的内部处理都是小端字节序。 但是,人类还是习惯读写大端字节序。所以,除了计算机的内部处理,其他的场合几乎都是大端字节序,比如网络传输和文件储存 ## 举例 ### 大端字节序处理 16位整数 **以此公式转换** `x = buf[offset] * 256 + buf[offset+1];` `buf`是整个数据块在内存中的起始地址,`offset`是当前正在读取的位置。第一个字节乘以256,再加上第二个字节,就是大端字节序的值 **使用逻辑运算符表示** `x = buf[offset]<<8 | buf[offset+1];` 第一个字节左移8位(即后面添8个`0`),然后再与第二个字节进行或运算 ### 以小端字节处理 16位整数 `x = buf[offset+1] * 256 + buf[offset];` ### 32位整数 ``` /* 大端字节序 */ i = (data[3]<<0) | (data[2]<<8) | (data[1]<<16) | (data[0]<<24); /* 小端字节序 */ i = (data[0]<<0) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24); ``` ## go 实现 小端序,大端序 ``` a :=int32(65535) b :=int32(65535) buf :=new(bytes.Buffer) binary.Write(buf,binary.LittleEndian,a) fmt.Printf("%+v\n", buf.Bytes()) // [255 255 0 0] buf2 :=new(bytes.Buffer) binary.Write(buf2,binary.BigEndian,b) fmt.Printf("%+v\n", buf2.Bytes()) // [0 0 255 255] ```