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

时间:2018-06-05 08:50:49

标签: c# c++

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

  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 = "\x02\x01C" + data;

    //ETX=0x03 
    data += "\x03";
    data += (char)calculateNL20CheckSum(data);
    data += "\r\n";

    return data;
}

public static byte calculateNL20CheckSum(string data)
{
    byte chk = 0;

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

    return chk;
}

在发送

之前,字符串将转换为字节数组

bytes = data.Select(c =&gt;(byte)c)。ToArray(); 现在的问题是C#代码永远不会从设备上获得这些请求的响应。它确实将其他数据发送回波特率以及所有正确的数据。

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

成了

\ x02 \ x01C data \ x03 checksum \ r \ n

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

2 个答案:

答案 0 :(得分:2)

这是一个奇怪的。和往常一样,我创建了一个单元测试。然后我使用C ++ CLR构建了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看起来很熟悉......

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

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

答案 1 :(得分:1)

嗯......你的问题可能是某些代码使用Encoding.ASCII.GetBytes(finalString)最终将string转换为byte[],但校验和可能是&gt; = 0x7F,所以非ASCII字符。在string之后手动将byte[]转换为Generate

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;

或者您可以使用Encoding.GetEncoding("iso-8859-1")映射值0x00-0xFF来解码值0x0000-0x00FF

注意Pete Kirkham,除非您有一些data字符&gt; 0x7F,校验和将是&lt; 0x7F的。这是因为^运算符只返回1(1 ^ 0)或(0 ^ 1),所以你必须将某位的8位置为1,校验和的8位为1。