云计算百科
云计算领域专业知识百科平台

C++ 工控通用:32 位 DINT 四种字节序一键转换函数

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);

赞(0)
未经允许不得转载:网硕互联帮助中心 » C++ 工控通用:32 位 DINT 四种字节序一键转换函数
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!