字节序大小端科普

一句话理解

字节序(Endianness) :一个多字节数据(如 int、float)在内存中按什么顺序存放各个字节。

看低地址放的是"高有效字节"还是"低有效字节":

  • 大端序 Big-endian :低地址放高有效字节(MSB)
  • 小端序 Little-endian :低地址放低有效字节(LSB)

口诀:大端"高低对应",小端"低低对应"------都看低地址。


经典例子

32 位整数:

c 复制代码
uint32_t x = 0x12345678;

其中:

  • 最高有效字节 MSB = 0x12
  • 最低有效字节 LSB = 0x78

假设从地址 0x1000 开始存放:

地址 大端序 小端序
0x1000 低地址 12 78
0x1001 34 56
0x1002 56 34
0x1003 高地址 78 12

所以:

  • 大端内存:12 34 56 78
  • 小端内存:78 56 34 12

注意:大小端只影响多字节对象内部字节的排列 ,不影响数组元素顺序,也不影响字符串 "AB" 的 ASCII 字节 41 42。字节内部的位顺序通常也不因此改变。


为什么会有大小端?

主要是 CPU 设计选择和历史原因:

  • 大端:内存里的字节顺序和人写数字的顺序一致,阅读调试直观。
  • 小端:低地址就是低字节,做低位截断、类型转换、某些算术访问更方便。

现代常见情况:

  • x86 / x86_64:小端
  • 常见 ARM:通常小端,但架构支持可配置
  • RISC-V:常见小端
  • 网络协议:规定使用大端,即"网络字节序"
  • Java ByteBuffer 默认大端;JVM class 文件采用大端
  • PNG 等部分文件格式规定大端;ELF 文件头里有字段标识端序

如何判断本机字节序

简单 C 代码:

c 复制代码
#include <stdint.h>
#include <stdio.h>

int main(void) {
    uint16_t x = 0x0001;
    unsigned char *p = (unsigned char *)&x;

    if (p[0] == 1)
        printf("小端\n");
    else
        printf("大端\n");

    return 0;
}

原因:0x0001 的低字节是 0x01,高字节是 0x00。

  • 小端:低地址放 01,所以 p[0] == 1
  • 大端:低地址放 00,所以 p[0] == 0

也可以用联合体判断,但工程上更推荐用 memcpy 避免别名/对齐争议。


网络字节序

TCP/IP 协议中的多字节字段规定为大端序 ,称为网络字节序。

C 中常用转换函数:

c 复制代码
#include <arpa/inet.h>  // Linux/Unix
// Windows 用 winsock2.h

uint16_t net_port = htons(8080);      // host to network short,16 位
uint32_t net_addr = htonl(0x7F000001); // host to network long,32 位

uint16_t host_port = ntohs(net_port);
uint32_t host_addr = ntohl(net_addr);

记忆:

  • htons / htonl:主机序 → 网络序
  • ntohs / ntohl:网络序 → 主机序
  • 如果主机本来就是大端,这些函数通常不改变字节;小端主机会交换字节

注意:"网络字节序 = 大端"是通用规定,但具体协议仍要看协议文档 。64 位转换可能需要 htobe64 / be64toh 或自己实现。


实际开发中的坑

  1. 不要直接把结构体 memcpy 到网络或文件

    • 结构体可能有填充字节、对齐差异
    • 字段端序可能不同
    • 应逐字段按协议显式序列化
  2. 跨平台二进制文件要明确端序

    • 文件格式规范说大端就按大端读写
    • 例如读 PNG 的 4 字节长度字段,要按大端解析
  3. 文本协议通常不涉及多字节整数端序

    • 单字节 ASCII 不受影响
    • 但 UTF-16 等多字节编码有端序问题,常用 BOM 标识
  4. 调试器看到"反了"很常见

    • 在 x86 小端机上,0x12345678 的内存窗口常显示为 78 56 34 12
  5. 位域布局、联合体类型双关与端序/编译器实现有关

    • 不要依赖它们做跨平台二进制协议

总结

  • 大端:低地址放高字节,内存顺序像人读数字。
  • 小端:低地址放低字节,x86 常见。
  • 网络字节序是大端,跨主机通信要转换。
  • 跨平台数据交换必须显式规定端序,不要假设对方和自己一样。
  • 判断口诀:看低地址放的是高字节还是低字节。
相关推荐
会编程的小孩1 小时前
C++ 子集
c++
SunkingYang2 小时前
C++20 vs C++17:新特性对比与用法指南
c++·c++20·特性·版本·新特性·对比·c++17
前进吧-程序员2 小时前
C++20 协程入门实战:从 co_await 到一个 100 行的异步任务调度器
网络·c++·c++20
前进吧-程序员2 小时前
实战:C++20 协程 + io_uring 写一个 400 行的 echo server
网络·c++·c++20
青少儿编程课堂6 小时前
蓝桥杯青少组 + 全国青少年信息素养大赛 + 电子学会图形化考级|校园推箱子大挑战解析
c++·python·算法·bfs·信息学竞赛
多弗朗皮卡丘7 小时前
C++STL之空间配置器
开发语言·c++·内存池·空间配置器
牵猫散步的鱼儿7 小时前
Demosaic 和 Remosaic
c++
CodeYp20197 小时前
第19讲:封装红黑树实现 mymap 和 myset
开发语言·c++·红黑树
孙鹏宇.8 小时前
C++类型转换
c++