在Indy C++ Builder中解析BCD格式字节的优雅方法求助
解析BCD格式消息长度的优雅实现
我在解析接收消息的长度字段,该字段采用BCD格式。调用ReadSmallInt()方法时,得到的是十六进制数值而非BCD转换后的十进制值。比如给定以下消息:
00 84 60 00 00 00 19 02 10 70 38 00 00 0E C0 00 00 16 45 93 56 00 01 79 16 62 00 00 00 00 00 00 08 00 00 00 00 02 10 43 02 04 02 35 31 35 31 35 31 35 31 35 31 35 31 53 41 4C 45 35 31 30 30 31 32 33 34 35 36 37 38 31 32 33 34 35 36 37 38 39 30 31 32 33
我预期ReadSmallInt()返回84,但实际得到132(这是按十六进制直接解析的正确结果)。之前看到过相关说法称ReadSmallInt()能读取BCD值,但实际不符。我已经用临时方法解决了问题,但想找更优雅的实现方式,当前临时代码如下:
int calculated_length; // 获取十六进制格式的长度值 calculated_length = AContext->Connection->IOHandler->ReadSmallInt(); // 将十六进制二进制值转为十六进制字符串 UnicodeString bcdLength = UnicodeString().sprintf(L"%04x", calculated_length); // 将十六进制字符串转为整数 calculated_length = bcdLength.ToInt(); ucBuffer.Length = calculated_length -2; AContext->Connection->IOHandler->ReadBytes(ucBuffer, calculated_length - 2);
优雅实现方案
临时方案通过字符串中转实现BCD转换,效率较低。可以直接通过位运算完成BCD到十进制的转换,代码更简洁且性能更优:
首先实现一个BCD字节转整数的工具函数:
// 单字节BCD转十进制整数 int BCDByteToInt(unsigned char bcdByte) { // 高4位对应十位,低4位对应个位 return ((bcdByte >> 4) * 10) + (bcdByte & 0x0F); }
然后替换原临时代码:
// 读取原始BCD字节(强转为unsigned char避免符号位干扰) unsigned char bcdLengthByte = static_cast<unsigned char>(AContext->Connection->IOHandler->ReadSmallInt()); // 直接转换为十进制长度 int calculated_length = BCDByteToInt(bcdLengthByte); ucBuffer.Length = calculated_length - 2; AContext->Connection->IOHandler->ReadBytes(ucBuffer, calculated_length - 2);
如果后续遇到多字节的BCD长度字段,可扩展工具函数处理,例如双字节BCD转换:
// 双字节BCD转十进制整数 int BCDWordToInt(unsigned short bcdWord) { return ((bcdWord >> 12) * 1000) + (((bcdWord >> 8) & 0x0F) * 100) + (((bcdWord >> 4) & 0x0F) * 10) + (bcdWord & 0x0F); }
内容的提问来源于stack exchange,提问作者Beto
相关产品推荐
相关产品推荐

