嵌入式开发必看:彻底搞懂大小端(Endian)原理、判断与实战示例
·
前言
在嵌入式开发、网络通信、数据存储、驱动开发中,大小端问题是绕不开的核心知识点。很多新手遇到数据解析错误、串口收发乱码、多字节数据读写异常,90%都是大小端不匹配导致的。
本文用最通俗的语言+完整可运行代码+实战场景,带你彻底吃透大小端,干货满满!
一、什么是大小端?
1. 核心定义
大小端 = 计算机/MCU 存储 多字节数据 的字节顺序规则。
注意:
- 单字节数据(char) 不存在大小端问题!
- 只有 int、short、long、float 等多字节类型 才会区分大小端。
2. 两个关键概念
-
大端模式(Big-Endian,BE)
数据的高字节 存储在低地址,低字节存储在高地址。
✅ 符合人类阅读习惯。 -
小端模式(Little-Endian,LE)
数据的低字节 存储在低地址,高字节存储在高地址。
✅ 符合CPU运算机制,是主流嵌入式平台默认模式。
二、举个最经典的例子(一看就懂)
我们用一个 16位短整型数据 举例:
uint16_t data = 0x1234;
数据拆分:
- 高字节:
0x12 - 低字节:
0x34
假设存储起始地址:0x0000
1. 大端存储(BE)
| 内存地址 | 0x0000(低地址) | 0x0001(高地址) |
|---|---|---|
| 存储内容 | 0x12(高字节) | 0x34(低字节) |
2. 小端存储(LE)
| 内存地址 | 0x0000(低地址) | 0x0001(高地址) |
|---|---|---|
| 存储内容 | 0x34(低字节) | 0x12(高字节) |
32位数据例子
uint32_t data = 0x12345678;
- 大端:
12 34 56 78 - 小端:
78 56 34 12
三、常见平台的大小端规则
1. 小端模式(绝大多数嵌入式MCU)
- ARM(STM32、NXP、GD32等全部Cortex-M内核)
- x86 / x86_64(PC电脑、笔记本)
- RISC-V
2. 大端模式
- 老式PowerPC
- 部分网络协议(网络字节序统一使用大端)
- 某些专用DSP
重要结论
STM32开发 = 小端模式!
电脑CPU = 小端模式!
网络通信 = 必须转大端!
四、手写代码:判断当前设备是大端还是小端
这是嵌入式笔试、面试必考题目,代码可直接运行。
方法:利用联合体(union)特性
union 所有成员共享同一块内存,我们可以用char单字节读取int数据的第一个字节。
#include <stdio.h>
#include <stdint.h>
// 判断大小端函数
int check_endian(void)
{
union {
uint16_t data;
uint8_t bytes[2];
} test;
test.data = 0x1234;
// 低地址存储的是低字节 0x34 → 小端
if (test.bytes[0] == 0x34) {
return 1; // 小端
}
// 低地址存储的是高字节 0x12 → 大端
else {
return 0; // 大端
}
}
int main(void)
{
if (check_endian()) {
printf("当前设备:小端模式(Little-Endian)\n");
} else {
printf("当前设备:大端模式(Big-Endian)\n");
}
return 0;
}
运行结果(PC/STM32)
当前设备:小端模式(Little-Endian)
五、大小端转换函数(嵌入式必备工具)
在串口、CAN、以太网、SPI、I2C通信时,必须做大小端转换!
1. 16位数据大小端互换
uint16_t swap16(uint16_t data)
{
return ((data << 8) & 0xFF00) | ((data >> 8) & 0x00FF);
}
2. 32位数据大小端互换
uint32_t swap32(uint32_t data)
{
return ((data << 24) & 0xFF000000) |
((data << 8) & 0x00FF0000) |
((data >> 8) & 0x0000FF00) |
((data >> 24) & 0x000000FF);
}
示例演示
uint16_t a = 0x1234;
uint16_t b = swap16(a); // b = 0x3412
uint32_t x = 0x12345678;
uint32_t y = swap32(x); // y = 0x78563412
六、嵌入式实战:大小端导致的BUG(高频坑点)
场景1:串口发送16位数据
MCU(小端)发送 0x1234,直接强转char发送:
uint8_t buf[2];
uint16_t data = 0x1234;
buf[0] = ((uint8_t *)&data)[0];
buf[1] = ((uint8_t *)&data)[1];
实际发送:0x34 0x12
上位机 expecting:0x12 0x34
✅ 解决:发送前用 swap16() 转换
场景2:网络通信(Socket)
网络协议规定:网络字节序 = 大端
所以:
- 发送:小端 → 大端
- 接收:大端 → 小端
Linux/STM32 标准库函数:
htons() // 主机转网络 16位
htonl() // 主机转网络 32位
ntohs() // 网络转主机 16位
ntohl() // 网络转主机 32位
七、总结(面试/笔记必背)
- 单字节无大小端,多字节才有
- 大端:高字节存低地址(人类习惯)
- 小端:低字节存低地址(CPU/MCU主流)
- STM32/ARM/x86 = 小端
- 网络通信 = 必须使用大端
- 大小端不匹配 = 数据解析错误、通信乱码
结束语
大小端是嵌入式开发的基础核心知识点,理解原理+会写判断函数+会写转换函数,基本能应对99%的开发场景。
如果这篇文章对你有帮助,欢迎点赞、收藏、转发~
我会持续更新嵌入式干货!
更多推荐

所有评论(0)