从 C++ 转换的 C# 代码不起作用

C# code converted from C++ not working

本文关键字:代码 不起作用 C++ 转换      更新时间:2023-10-16

考虑以下通过RS232将数据发送到设备的C++代码。

strcpy(m_MsgBytes, "SRT1");
iTmp = finalizeNL20Message(m_MsgBytes, 4);
int CVTSSLTNL20Message::finalizeNL20Message(BYTE *pMsgData, int iInLen)
{
BYTE ucMsg[MAX_MESSAGE_LENGTH];
ucMsg[0]  = MSG_STX; // 0x02
ucMsg[1]  = NL20_BLOCK_ID; // ox01
ucMsg[2]  = ATTR_CMD; // 'C'
memcpy(&ucMsg[3], pMsgData, iInLen);
ucMsg[3 + iInLen] = MSG_ETX;
ucMsg[4 + iInLen] = calculateNL20Checksum(ucMsg, 4 + iInLen);
ucMsg[5 + iInLen] = MSG_CR;
ucMsg[6 + iInLen] = MSG_LF;
memcpy(pMsgData, ucMsg, 7 + iInLen);
return 7 + iInLen;
}
BYTE CVTSSLTNL20Message::calculateNL20Checksum(const BYTE *pData, int iInLen)
{
BYTE ucChk = 0;
for (int iCnt = 0; iCnt < iInLen; iCnt++)
ucChk = ucChk ^ pData[iCnt];
return ucChk;
}

我用 C# 重写了这段代码,如下所示:

public static string Generate()
{
return RIONNLHelper.FinalizeMessage("SRT1");
}
public static string FinalizeMessage(string data)
{
//STX=0x02 NL20BLOCKID=0x01 Command=C (Command from computer)
data = "x02x01C" + data;
//ETX=0x03 
data += "x03";
data += (char)calculateNL20CheckSum(data);
data += "rn";
return data;
}
public static byte calculateNL20CheckSum(string data)
{
byte chk = 0;
foreach (byte b in Encoding.ASCII.GetBytes(data))
{
chk ^= b;
}
return chk;
}

并且字符串在发送前转换为字节数组

字节 = 数据。选择(c=>(byte(c(.ToArray((; 现在的问题是,C# 代码永远不会从设备获得对这些请求的响应。它确实会发送回其他数据,因此波特率和所有正确的数据。

我对缓冲区从C++代码转换有些疑问。 0x020x01C 数据 0x03校验和 \r

成为

\x02\x01C 数据 \x03 校验和 \r

否则,重写校验和计算是否正确?首先计算字节的校验和,然后转换回字符

这是一个奇怪的问题。与往常一样,我创建了一个单元测试。然后我使用 CLR 构建了C++版本C++并进行测试以将输出与您的输入"SRT1"进行比较。最初,它失败了

C++ version:  02 01 43 53 52 54 31 03 27 0d 0a 
C# version:   02 1c 53 52 54 31 03 79 0d 0a

那个1C看起来相当熟悉...

错误似乎在于假设字符串"x02x01C" + data;与"x02" + "x01" + "C" + data;相同,而十六进制转义将继续解释数字,直到找到不是十六进制数字的字符。因此,"C"成为十六进制转义的一部分。

分解文字允许解析器将"C"解析为单独的字符,然后单元测试通过。

嗯...您的问题可能是某些代码使用Encoding.ASCII.GetBytes(finalString)最终将string转换为byte[],但校验和可能是>= 0x7F,因此是非 ASCII 字符。在Generate后手动将string转换为byte[],如下所示:

string result = Generate();
byte[] bytes = new byte[result.Length];
for (int i = 0; i < result.Length; i++)
{
bytes[i] = (byte)result[i];
}

只是为了确保更改:

foreach (byte b in Encoding.ASCII.GetBytes(data))
{
chk ^= b;

foreach (char ch in data)
{
chk ^= (byte)ch;

或者,您可以使用将值0x00-0xFF映射到 unicode 值0x0000-0x00FFEncoding.GetEncoding("iso-8859-1")

Pete Kirkham所述,除非您对字符>0x7F有一些data,否则校验和将被<0x7F。这是因为^运算符将仅返回 (1 ^ 0( 或 (0 ^ 1( 的 1,因此您必须在某个地方将 8 位位于 1 处,才能使 8 位为 1 的校验和。