C++ 工控通用:32 位 DINT 四种字节序一键转换函数(ABCD/CDAB/BADC/DCBA)
前言
做 Modbus TCP/RTU 工控上位机开发,最头疼的问题之一就是32 位数据字节序不统一。 PLC 的 DINT(32 位有符号整数)、REAL(32 位浮点数)占用 2 个连续 16 位寄存器,不同厂商设备字节排布五花八门:
- 西门子标准:ABCD(大端)
- 汇川、台达、大量国产机器人:CDAB、BADC
- 部分小型控制器:DCBA(小端)
Windows 自带htonl/ntohl仅支持大小端转换,无法覆盖 CDAB、BADC 这两种双字交换模式。 为此封装一个通用转换函数,一次调用输出 4 种主流字节序,调试、适配多品牌 PLC 非常方便。
运行环境:Windows + MSVC / Qt MSVC(x86/x64)
四种字节序定义说明
假设 32 位原始整数:0x11223344
plaintext
bit31~24(A)
bit23~16(B)
bit15~8(C)
bit7~0(D)
A=0x11 ,
B=0x22 ,
C=0x33 ,
D=0x44
表格
| ABCD | A B C D | 0x11223344 | 西门子、标准大端 |
| CDAB | C D A B | 0x33441122 | 大量国产 PLC、机器人 |
| BADC | B A D C | 0x22114433 | 部分运动控制器、仪表 |
| DCBA | D C B A | 0x44332211 | 小端模式 |
完整源码
/**
* @brief 32位DINT四种字节序转换函数
* @param input 原始32位有符号整数(PLC DINT)
* @param ABCD 输出 A B C D 原始序
* @param CDAB 输出 C D A B
* @param BADC 输出 B A D C
* @param DCBA 输出 D C B A
* @note 仅Windows MSVC环境使用,适配Modbus上位机通信
*/
void ABCD_SWAP(int input, int* ABCD, int* CDAB, int* BADC, int* DCBA)
{
// 空指针保护,防止外部异常调用导致程序崩溃
if (!ABCD || !CDAB || !BADC || !DCBA)
return;
unsigned char A, B, C, D;
unsigned int uIn = (unsigned int)input;
*ABCD = input;
// 拆分4个字节
D = uIn & 0xFF;
C = (uIn >> 8) & 0xFF;
B = (uIn >> 16) & 0xFF;
A = (uIn >> 24) & 0xFF;
// 重组四种字节顺序
*CDAB = (unsigned int)C << 24 | (unsigned int)D << 16 | (unsigned int)A << 8 | B;
*BADC = (unsigned int)B << 24 | (unsigned int)A << 16 | (unsigned int)D << 8 | C;
*DCBA = (unsigned int)D << 24 | (unsigned int)C << 16 | (unsigned int)B << 8 | A;
}
调用示例 & 单元测试
#include <iostream>
using namespace std;
int main()
{
int ABCD, CDAB, BADC, DCBA;
// 测试样例 0x11223344
ABCD_SWAP(0x11223344, &ABCD, &CDAB, &BADC, &DCBA);
printf("ABCD = 0x%08X\\n", (unsigned int)ABCD);
printf("CDAB = 0x%08X\\n", (unsigned int)CDAB);
printf("BADC = 0x%08X\\n", (unsigned int)BADC);
printf("DCBA = 0x%08X\\n", (unsigned int)DCBA);
return 0;
}
输出结果:
ABCD = 0x11223344
CDAB = 0x33441122
BADC = 0x22114433
DCBA = 0x44332211
关键技术要点说明
1. 为什么先转 unsigned int 拆分?
原始参数 int 是有符号类型。 如果数值为负数,直接 input >> 24 会触发算术右移(高位补 1),字节拆分出错。 先强制转为unsigned int,保证逻辑右移,高低字节拆分永远稳定。
2. 移位操作强制转换 unsigned int
unsigned char 直接左移 24 位会提升为有符号 int,存在符号溢出隐患。 (unsigned int)C << 24 保证移位全程无符号运算,规避未定义行为。
3. 空指针判断(工控软件必备)
上位机软件外部调用逻辑复杂,如果外部传入 nullptr,不做判断会直接触发访问异常、程序闪退。工业代码稳定性优先。
4. 拓展:同时支持 32 位浮点数 REAL
PLC 32 位浮点 REAL 同样 4 字节,这套转换逻辑完全通用。使用方式:
// ==========打印验证部分==========
float realVal = 123.456f;
// 原始方式:注意标准C++属于UB,嵌入式经常这么写
int raw = *(int*)(&realVal);
int a,b,c,d;
ABCD_SWAP(raw, &a, &b, &c, &d);
printf("float原值 = %f\\n", realVal);
printf("原始32位raw(十六进制) = 0x%08X\\n", (unsigned int)raw);
printf("拆分后4个字节:\\n");
printf("a = 0x%02X \\nb = 0x%02X \\nc = 0x%02X \\nd = 0x%02X\\n", a,b,c,d);

网硕互联帮助中心





评论前必须登录!
注册