- #ifndef ENDIAN_UTILS_H
- #define ENDIAN_UTILS_H
- #include <stdint.h>
- #include <stddef.h>
- #include <stdbool.h>
- // 端序检测:运行时检测(默认,兼容性好)
- // 若需编译时检测,可注释下面的宏,取消注释上面的
- // #define ENDIAN_IS_LITTLE 1
- // #define ENDIAN_IS_BIG 0
- bool endian_is_little(void);
- // 16位单值大小端互换
- uint16_t endian_swap16(uint16_t val);
- // 16位单值:小端→大端
- uint16_t endian_le16_to_be16(uint16_t le_val);
- // 16位单值:大端→小端
- uint16_t endian_be16_to_le16(uint16_t be_val);
- // 32位单值大小端互换
- uint32_t endian_swap32(uint32_t val);
- // 32位单值:小端→大端
- uint32_t endian_le32_to_be32(uint32_t le_val);
- // 32位单值:大端→小端
- uint32_t endian_be32_to_le32(uint32_t be_val);
- // 64位单值大小端互换
- uint64_t endian_swap64(uint64_t val);
- // 64位单值:小端→大端
- uint64_t endian_le64_to_be64(uint64_t le_val);
- // 64位单值:大端→小端
- uint64_t endian_be64_to_le64(uint64_t be_val);
- // 16位数组批量大小端互换
- void endian_swap16_array(uint16_t *arr, size_t count);
- // 16位数组批量:小端→大端
- void endian_le16_to_be16_array(uint16_t *arr, size_t count);
- // 16位数组批量:大端→小端
- void endian_be16_to_le16_array(uint16_t *arr, size_t count);
- // 32位数组批量大小端互换
- void endian_swap32_array(uint32_t *arr, size_t count);
- // 32位数组批量:小端→大端
- void endian_le32_to_be32_array(uint32_t *arr, size_t count);
- // 32位数组批量:大端→小端
- void endian_be32_to_le32_array(uint32_t *arr, size_t count);
- // 64位数组批量大小端互换
- void endian_swap64_array(uint64_t *arr, size_t count);
- // 64位数组批量:小端→大端
- void endian_le64_to_be64_array(uint64_t *arr, size_t count);
- // 64位数组批量:大端→小端
- void endian_be64_to_le64_array(uint64_t *arr, size_t count);
- #endif
实现文件(endian_utils.c)
- #include "endian_utils.h"
- // 运行时端序检测
- bool endian_is_little(void) {
- union {
- uint16_t u16;
- uint8_t u8[2];
- } test_union = {0x1234};
- return (test_union.u8[0] == 0x34);
- }
- // 16位单值大小端互换
- uint16_t endian_swap16(uint16_t val) {
- return ((val & 0x00FF) << 8) | ((val & 0xFF00) >> 8);
- }
- // 16位单值:小端→大端
- uint16_t endian_le16_to_be16(uint16_t le_val) {
- return endian_is_little() ? endian_swap16(le_val) : le_val;
- }
- // 16位单值:大端→小端
- uint16_t endian_be16_to_le16(uint16_t be_val) {
- return endian_is_little() ? endian_swap16(be_val) : be_val;
- }
- // 32位单值大小端互换
- uint32_t endian_swap32(uint32_t val) {
- return ((val & 0x000000FF) << 24) |
- ((val & 0x0000FF00) << 8) |
- ((val & 0x00FF0000) >> 8) |
- ((val & 0xFF000000) >> 24);
- }
- // 32位单值:小端→大端
- uint32_t endian_le32_to_be32(uint32_t le_val) {
- return endian_is_little() ? endian_swap32(le_val) : le_val;
- }
- // 32位单值:大端→小端
- uint32_t endian_be32_to_le32(uint32_t be_val) {
- return endian_is_little() ? endian_swap32(be_val) : be_val;
- }
- // 64位单值大小端互换
- uint64_t endian_swap64(uint64_t val) {
- return ((val & 0x00000000000000FFULL) << 56) |
- ((val & 0x000000000000FF00ULL) << 40) |
- ((val & 0x0000000000FF0000ULL) << 24) |
- ((val & 0x00000000FF000000ULL) << 8) |
- ((val & 0x000000FF00000000ULL) >> 8) |
- ((val & 0x0000FF0000000000ULL) >> 24) |
- ((val & 0x00FF000000000000ULL) >> 40) |
- ((val & 0xFF00000000000000ULL) >> 56);
- }
- // 64位单值:小端→大端
- uint64_t endian_le64_to_be64(uint64_t le_val) {
- return endian_is_little() ? endian_swap64(le_val) : le_val;
- }
- // 64位单值:大端→小端
- uint64_t endian_be64_to_le64(uint64_t be_val) {
- return endian_is_little() ? endian_swap64(be_val) : be_val;
- }
- // 16位数组批量大小端互换
- void endian_swap16_array(uint16_t *arr, size_t count) {
- for (size_t i = 0; i < count; i++) {
- arr[i] = endian_swap16(arr[i]);
- }
- }
- // 16位数组批量:小端→大端
- void endian_le16_to_be16_array(uint16_t *arr, size_t count) {
- if (endian_is_little()) {
- endian_swap16_array(arr, count);
- }
- }
- // 16位数组批量:大端→小端
- void endian_be16_to_le16_array(uint16_t *arr, size_t count) {
- if (endian_is_little()) {
- endian_swap16_array(arr, count);
- }
- }
- // 32位数组批量大小端互换
- void endian_swap32_array(uint32_t *arr, size_t count) {
- for (size_t i = 0; i < count; i++) {
- arr[i] = endian_swap32(arr[i]);
- }
- }
- // 32位数组批量:小端→大端
- void endian_le32_to_be32_array(uint32_t *arr, size_t count) {
- if (endian_is_little()) {
- endian_swap32_array(arr, count);
- }
- }
- // 32位数组批量:大端→小端
- void endian_be32_to_le32_array(uint32_t *arr, size_t count) {
- if (endian_is_little()) {
- endian_swap32_array(arr, count);
- }
- }
- // 64位数组批量大小端互换
- void endian_swap64_array(uint64_t *arr, size_t count) {
- for (size_t i = 0; i < count; i++) {
- arr[i] = endian_swap64(arr[i]);
- }
- }
- // 64位数组批量:小端→大端
- void endian_le64_to_be64_array(uint64_t *arr, size_t count) {
- if (endian_is_little()) {
- endian_swap64_array(arr, count);
- }
- }
- // 64位数组批量:大端→小端
- void endian_be64_to_le64_array(uint64_t *arr, size_t count) {
- if (endian_is_little()) {
- endian_swap64_array(arr, count);
- }
- }
二、使用方法
- 端序检测:调用 endian_is_little() 确认当前系统端序(可选,转换函数已自动适配);
- 单值转换:根据需求调用对应函数(如 TCP/IP 网络数据用 endian_be32_to_le32() 转成本地小端);
- 数组批量转换:适合处理传感器数据包、固件配置块等连续多字节数据,直接传数组指针和元素个数即可。
三、移植方法
- 将 endian_utils.c 和 endian_utils.h 复制到 e²s 工程目录(如 src/utils/);
- 在 e²s 中右键工程 → Add Files,将 endian_utils.c 加入编译;
- 若需编译时端序检测(节省 1-2 字节 Flash 和极短的运行时间),可在头文件中注释运行时检测的宏,取消注释编译时检测的宏(需提前确认目标系统端序);
- 在需要使用的文件中包含头文件:#include "endian_utils.h";
- 按场景调用对应函数即可。
三、调用函数代码验证
本次贴合瑞萨 RATCP/IP 网络通信 + 跨设备 Flash 读取的真实场景:
验证代码(基于瑞萨 RA6M5 + e²s IDE)
- #include "hal_data.h"
- #include "endian_utils.h"
- #include <stdio.h>
- #include <string.h>
- void uart_print(const char *str) {
- R_SCI_UART_Write(&g_uart0_ctrl, (uint8_t *)str, strlen(str));
- }
- void endian_test(void) {
- char buf[256];
- union {
- uint16_t u16;
- uint8_t u8[2];
- } test16;
- union {
- uint32_t u32;
- uint8_t u8[4];
- } test32;
- union {
- uint64_t u64;
- uint8_t u8[8];
- } test64;
- uint16_t arr16[] = {0x1234, 0x5678, 0x9ABC};
- uint32_t arr32[] = {0x12345678, 0x9ABCDEF0};
- // 1. 端序检测
- uart_print("--- 1. 端序检测 ---\r\n");
- snprintf(buf, sizeof(buf), "当前系统端序:%s\r\n\r\n", endian_is_little() ? "小端(Little Endian)" : "大端(Big Endian)");
- uart_print(buf);
- // 2. 16位单值转换+内存验证
- uart_print("--- 2. 16位单值转换+内存验证 ---\r\n");
- test16.u16 = 0x1234;
- snprintf(buf, sizeof(buf), "本地小端内存:%02X %02X\r\n", test16.u8[0], test16.u8[1]);
- uart_print(buf);
- uint16_t be16 = endian_le16_to_be16(test16.u16);
- // 用临时union看大端内存(注意:be16在本地小端系统中存的是“大端的数值”,内存顺序还是小端,需手动反转看逻辑)
- snprintf(buf, sizeof(buf), "转换后大端数值:0x%04X,逻辑内存:%02X %02X\r\n\r\n", be16, (uint8_t)(be16 >> 8), (uint8_t)(be16 & 0xFF));
- uart_print(buf);
- // 3. 32位单值转换+内存验证
- uart_print("--- 3. 32位单值转换+内存验证 ---\r\n");
- test32.u32 = 0x12345678;
- snprintf(buf, sizeof(buf), "本地小端内存:%02X %02X %02X %02X\r\n", test32.u8[0], test32.u8[1], test32.u8[2], test32.u8[3]);
- uart_print(buf);
- uint32_t be32 = endian_le32_to_be32(test32.u32);
- snprintf(buf, sizeof(buf), "转换后大端数值:0x%08X,逻辑内存:%02X %02X %02X %02X\r\n\r\n", be32, (uint8_t)(be32 >> 24), (uint8_t)((be32 >> 16) & 0xFF), (uint8_t)((be32 >> 8) & 0xFF), (uint8_t)(be32 & 0xFF));
- uart_print(buf);
- // 4. 64位单值转换+内存验证
- uart_print("--- 4. 64位单值转换+内存验证 ---\r\n");
- test64.u64 = 0x123456789ABCDEF0ULL;
- snprintf(buf, sizeof(buf), "本地小端内存:%02X %02X %02X %02X %02X %02X %02X %02X\r\n", test64.u8[0], test64.u8[1], test64.u8[2], test64.u8[3], test64.u8[4], test64.u8[5], test64.u8[6], test64.u8[7]);
- uart_print(buf);
- uint64_t be64 = endian_le64_to_be64(test64.u64);
- snprintf(buf, sizeof(buf), "转换后大端数值:0x%016llX,逻辑内存:%02X %02X %02X %02X %02X %02X %02X %02X\r\n\r\n", (unsigned long long)be64, (uint8_t)(be64 >> 56), (uint8_t)((be64 >> 48) & 0xFF), (uint8_t)((be64 >> 40) & 0xFF), (uint8_t)((be64 >> 32) & 0xFF), (uint8_t)((be64 >> 24) & 0xFF), (uint8_t)((be64 >> 16) & 0xFF), (uint8_t)((be64 >> 8) & 0xFF), (uint8_t)(be64 & 0xFF));
- uart_print(buf);
- // 5. 16位数组批量转换
- uart_print("--- 5. 16位数组批量转换 ---\r\n");
- snprintf(buf, sizeof(buf), "本地小端数组:");
- uart_print(buf);
- for (size_t i = 0; i < sizeof(arr16)/sizeof(arr16[0]); i++) {
- snprintf(buf, sizeof(buf), "0x%04X ", arr16[i]);
- uart_print(buf);
- }
- uart_print("\r\n");
- endian_le16_to_be16_array(arr16, sizeof(arr16)/sizeof(arr16[0]));
- snprintf(buf, sizeof(buf), "转换后大端数值数组:");
- uart_print(buf);
- for (size_t i = 0; i < sizeof(arr16)/sizeof(arr16[0]); i++) {
- snprintf(buf, sizeof(buf), "0x%04X ", arr16[i]);
- uart_print(buf);
- }
- uart_print("\r\n\r\n");
- // 6. 32位数组批量转换
- uart_print("--- 6. 32位数组批量转换 ---\r\n");
- snprintf(buf, sizeof(buf), "本地小端数组:");
- uart_print(buf);
- for (size_t i = 0; i < sizeof(arr32)/sizeof(arr32[0]); i++) {
- snprintf(buf, sizeof(buf), "0x%08X ", arr32[i]);
- uart_print(buf);
- }
- uart_print("\r\n");
- endian_le32_to_be32_array(arr32, sizeof(arr32)/sizeof(arr32[0]));
- snprintf(buf, sizeof(buf), "转换后大端数值数组:");
- uart_print(buf);
- for (size_t i = 0; i < sizeof(arr32)/sizeof(arr32[0]); i++) {
- snprintf(buf, sizeof(buf), "0x%08X ", arr32[i]);
- uart_print(buf);
- }
- uart_print("\r\n");
- }
- void hal_entry(void) {
- R_SCI_UART_Open(&g_uart0_ctrl, &g_uart0_cfg);
- endian_test();
- while (1);
- }
五、结果对比
我们通过串口助手验证数据与与其是否相符:
我们换一组数据继续验证:
新验证代码(直接替换原 endian_test 函数即可)
- void endian_test(void) {
- char buf[256];
- int16_t signed16_val;
- int32_t signed32_val;
- // 1. 端序环境确认
- uart_print("--- 1. 端序环境确认 ---\r\n");
- snprintf(buf, sizeof(buf), "当前系统端序:%s\r\n\r\n", endian_is_little() ? "小端(Little Endian,瑞萨RA默认)" : "大端(Big Endian)");
- uart_print(buf);
- // 2. Modbus温度寄存器解析(16位大端→小端)
- uart_print("--- 2. Modbus温度寄存器解析(16位大端→小端) ---\r\n");
- uint16_t temp_raw = 0xF401; // 小端系统读取到的原始值
- uint16_t temp_real = endian_be16_to_le16(temp_raw);
- snprintf(buf, sizeof(buf), "原始读取值:0x%04X,转换后正确值:0x%04X(十进制:%d,对应温度:%.1f℃)\r\n\r\n",
- temp_raw, temp_real, temp_real, temp_real / 10.0f);
- uart_print(buf);
- // 3. CAN总线32位流量数据解析(32位大端→小端)
- uart_print("--- 3. CAN总线32位流量数据解析(32位大端→小端) ---\r\n");
- uint32_t flow_raw = 0x78563412; // 小端系统读取到的原始值
- uint32_t flow_real = endian_be32_to_le32(flow_raw);
- snprintf(buf, sizeof(buf), "原始读取值:0x%08X,转换后正确值:0x%08X(十进制:%lu)\r\n\r\n",
- flow_raw, flow_real, flow_real);
- uart_print(buf);
- // 4. 负温度传感器数据解析(16位有符号负数,大端→小端)
- uart_print("--- 4. 负温度传感器数据解析(16位有符号负数) ---\r\n");
- uint16_t neg_temp_raw = 0xD8FF; // 小端系统读取到的原始值
- uint16_t neg_temp_u16 = endian_be16_to_le16(neg_temp_raw);
- signed16_val = (int16_t)neg_temp_u16;
- snprintf(buf, sizeof(buf), "原始读取值:0x%04X,转换后正确值:0x%04X(十进制:%d,对应温度:%.1f℃)\r\n\r\n",
- neg_temp_raw, neg_temp_u16, signed16_val, signed16_val / 1.0f);
- uart_print(buf);
- // 5. 负流量累计值解析(32位有符号负数,大端→小端)
- uart_print("--- 5. 负流量累计值解析(32位有符号负数) ---\r\n");
- uint32_t neg_flow_raw = 0x80FFFFFF; // 小端系统读取到的原始值
- uint32_t neg_flow_u32 = endian_be32_to_le32(neg_flow_raw);
- signed32_val = (int32_t)neg_flow_u32;
- snprintf(buf, sizeof(buf), "原始读取值:0x%08X,转换后正确值:0x%08X(十进制:%d)\r\n\r\n",
- neg_flow_raw, neg_flow_u32, signed32_val);
- uart_print(buf);
- // 6. Modbus批量读4个保持寄存器(16位数组批量大端→小端)
- uart_print("--- 6. Modbus批量寄存器解析(16位数组批量转换) ---\r\n");
- uint16_t modbus_arr[] = {0x0201, 0x0403, 0x0605, 0x0807};
- size_t arr16_len = sizeof(modbus_arr)/sizeof(modbus_arr[0]);
- // 打印原始数组
- snprintf(buf, sizeof(buf), "原始读取数组:");
- uart_print(buf);
- for (size_t i = 0; i < arr16_len; i++) {
- snprintf(buf, sizeof(buf), "0x%04X ", modbus_arr[i]);
- uart_print(buf);
- }
- uart_print("\r\n");
- // 批量转换
- endian_be16_to_le16_array(modbus_arr, arr16_len);
- // 打印转换后数组
- snprintf(buf, sizeof(buf), "转换后正确数组:");
- uart_print(buf);
- for (size_t i = 0; i < arr16_len; i++) {
- snprintf(buf, sizeof(buf), "0x%04X ", modbus_arr[i]);
- uart_print(buf);
- }
- uart_print("\r\n\r\n");
- // 7. 多通道传感器批量数据(32位数组批量大端→小端)
- uart_print("--- 7. 多通道传感器批量数据(32位数组批量转换) ---\r\n");
- uint32_t sensor_arr[] = {0x44332211, 0x88776655};
- size_t arr32_len = sizeof(sensor_arr)/sizeof(sensor_arr[0]);
- // 打印原始数组
- snprintf(buf, sizeof(buf), "原始读取数组:");
- uart_print(buf);
- for (size_t i = 0; i < arr32_len; i++) {
- snprintf(buf, sizeof(buf), "0x%08X ", sensor_arr[i]);
- uart_print(buf);
- }
- uart_print("\r\n");
- // 批量转换
- endian_be32_to_le32_array(sensor_arr, arr32_len);
- // 打印转换后数组
- snprintf(buf, sizeof(buf), "转换后正确数组:");
- uart_print(buf);
- for (size_t i = 0; i < arr32_len; i++) {
- snprintf(buf, sizeof(buf), "0x%08X ", sensor_arr[i]);
- uart_print(buf);
- }
- uart_print("\r\n\r\n");
- // 8. 边界极值验证
- uart_print("--- 8. 边界极值验证 ---\r\n");
- uint16_t u16_min = 0x0000, u16_max = 0xFFFF;
- uint32_t u32_min = 0x00000000, u32_max = 0xFFFFFFFF;
- snprintf(buf, sizeof(buf), "16位0x0000转换后:0x%04X\r\n", endian_swap16(u16_min));
- uart_print(buf);
- snprintf(buf, sizeof(buf), "16位0xFFFF转换后:0x%04X\r\n", endian_swap16(u16_max));
- uart_print(buf);
- snprintf(buf, sizeof(buf), "32位0x00000000转换后:0x%08X\r\n", endian_swap32(u32_min));
- uart_print(buf);
- snprintf(buf, sizeof(buf), "32位0xFFFFFFFF转换后:0x%08X\r\n", endian_swap32(u32_max));
- uart_print(buf);
- }
注意事项
- 端序检测的准确性:运行时检测用的是 union,符合 C 标准,兼容性 100%;
- 批量转换的数组指针:批量转换函数会直接修改原数组,若需保留原数组,可先复制一份再转换;
- 数值与内存的区别:转换函数返回的是 “目标端序的数值”,在本地小端系统中,这个数值的内存顺序还是小端,但逻辑上是目标端序的(比如 TCP/IP 发送时,直接把这个数值的内存发出去就是大端的逻辑内存);
- 资源占用:代码约 1KB Flash,无额外 RAM 缓冲区,适合所有 8/16/32/64 位 MCU;
- 适用场景:适合跨架构通信(TCP/IP、Modbus TCP、CAN FD 扩展帧)、跨设备 Flash 读取(如从 8051 的 Flash 读配置到 RA)、跨平台数据交换;
- 硬件加速:瑞萨 RA 系列部分高端型号(如 RA6M5)的 DMA 或加密引擎可能支持硬件大小端转换,后续有机会再分享~