C++ 校验和计算 - 所有字节的二进制补码和

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12238528/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 16:04:16  来源:igfitidea点击:

Checksum calculation - two’s complement sum of all bytes

c++algorithmchecksum

提问by Angus Comber

I have instructions on creating a checksum of a message described like this:

我有关于创建这样描述的消息校验和的说明:

The checksum consists of a single byte equal to the two's complement sum of all bytes starting from the “message type” word up to the end of the message block (excluding the transmitted checksum). Carry from the most significant bit is ignored.

校验和由一个字节组成,等于从“消息类型”字开始到消息块末尾(不包括传输的校验和)的所有字节的二进制补码和。忽略最高有效位的进位。

Another description I found was: The checksum value contains the twos complement of the modulo 256 sum of the other words in the data message (i.e., message type, message length, and data words). The receiving equipment may calculate the modulo 256 sum of the received words and add this sum to the received checksum word. A result of zero generally indicates that the message was correctly received.

我发现的另一个描述是:校验和值包含数据消息中其他字(即消息类型、消息长度和数据字)的模 256 和的二进制补码。接收设备可以计算接收到的字的模 256 和并将该和添加到接收到的校验和字。结果为零通常表示消息已正确接收。

I understand this to mean that I sum the value of all bytes in message (excl checksum), get modulo 256 of this number. get twos complement of this number and that is my checksum.

我理解这意味着我对消息中所有字节的值求和(不包括校验和),得到这个数字的模 256。得到这个数字的二进制补码,这就是我的校验和。

But I am having trouble with an example message example (from design doc so I must assume it has been encoded correctly).

但是我在使用示例消息示例时遇到了问题(来自设计文档,因此我必须假设它已正确编码)。

unsigned char arr[] = {0x80,0x15,0x1,0x8,0x30,0x33,0x31,0x35,0x31,0x30,0x33,0x30,0x2,0x8,0x30,0x33,0x35,0x31,0x2d,0x33,0x32,0x31,0x30,0xe};

So the last byte, 0xE, is the checksum. My code to calculate the checksum is as follows:

所以最后一个字节 0xE 是校验和。我计算校验和的代码如下:

bool isMsgValid(unsigned char arr[], int len) {
   int sum = 0;
   for(int i = 0; i < (len-1); ++i) {
      sum += arr[i];
   }
   //modulo 256 sum
   sum %= 256;

   char ch = sum;

   //twos complement
   unsigned char twoscompl = ~ch + 1;

   return arr[len-1] == twoscompl;
}


int main(int argc, char* argv[])
{
   unsigned char arr[] = {0x80,0x15,0x1,0x8,0x30,0x33,0x31,0x35,0x31,0x30,0x33,0x30,0x2,0x8,0x30,0x33,0x35,0x31,0x2d,0x33,0x32,0x31,0x30,0xe};
   int arrsize = sizeof(arr) / sizeof(arr[0]);

   bool ret = isMsgValid(arr, arrsize);

   return 0;
}

The spec is here:= http://www.sinet.bt.com/227v3p5.pdf

规范在这里:= http://www.sinet.bt.com/227v3p5.pdf

I assume I have misunderstood the algorithm required. Any idea how to create this checksum?

我想我误解了所需的算法。知道如何创建这个校验和吗?

Flippin spec writer made a mistake in their data example. Just spotted this then came back on here and found others spotted too. Sorry if I wasted your time. I will study responses because it looks like some useful comments for improving my code.

Flippin 规范作者在他们的数据示例中犯了一个错误。刚发现这个然后回到这里,发现其他人也被发现了。对不起,如果我浪费了你的时间。我将研究响应,因为它看起来像是一些对改进我的代码有用的注释。

回答by Emile Cormier

You miscopied the example message from the pdf you linked. The second parameter length is 9 bytes, but you used 0x08 in your code.

您从链接的 pdf 中错误地复制了示例消息。第二个参数长度为 9 个字节,但您在代码中使用了 0x08。

The document incorrectly states "8 bytes" in the third column when there are really 9 bytes in the parameter. The second column correctly states "00001001".

当参数中确实有 9 个字节时,文档在第三列中错误地指出了“8 个字节”。第二列正确指出“00001001”。

In other words, your test message should be:

换句话说,您的测试消息应该是:

{0x80,0x15,0x1,0x8,0x30,0x33,0x31,0x35,0x31,0x30,0x33,0x30, // param1
 0x2,0x9,0x30,0x33,0x35,0x31,0x2d,0x33,0x32,0x31,0x30,0xe}  // param2
     ^^^

With the correct message array, ret == truewhen I try your program.

使用正确的消息数组,ret == true当我尝试您的程序时。

回答by Pete Becker

Agree with the comment: looks like the checksum is wrong. Where in the .PDF is this data?

同意评论:看起来校验和是错误的。该数据在 .PDF 中的何处?

Some general tips:

一些一般提示:

Use an unsigned type as the accumulator; that gives you well-defined behavior on overflow, and you'll need that for longer messages. Similarly, if you store the result in a char variable, make it unsigned char.

使用无符号类型作为累加器;这为您提供了明确定义的溢出行为,并且您将需要更长的消息。同样,如果将结果存储在 char 变量中,请将其设为 unsigned char。

But you don't need to store it; just do the math with an unsigned type, complement the result, add 1, and mask off the high bits so that you get an 8-bit result.

但是你不需要存储它;只需使用无符号类型进行数学运算,对结果求补,加 1,然后屏蔽高位,从而得到 8 位结果。

Also, there's a trick here, if you're on hardware that uses twos-complement arithmetic: just add all of the values, including the checksum, then mask off the high bits; the result will be 0 if the input was correct.

此外,这里有一个技巧,如果您使用的是使用二进制补码算法的硬件:只需添加所有值,包括校验和,然后屏蔽高位;如果输入正确,结果将为 0。

回答by Pete Becker

The receiving equipment may calculate the modulo 256 sum of the received words and add this sum to the received checksum word.

接收设备可以计算接收到的字的模 256 和并将该和添加到接收到的校验和字。

It's far easier to use this condition to understand the checksum:

使用这个条件来理解校验和要容易得多:

{byte 0} + {byte 1} + ... + {last byte} + {checksum} = 0    mod 256
{checksum} = -( {byte 0} + {byte 1} + ... + {last byte} )   mod 256

As the others have said, you really should use unsigned types when working with individual bits. This is also true when doing modular arithmetic. If you use signed types, you leave yourself open to a rather largenumber of sign-related mistakes. OTOH, pretty much the only mistake you open yourself up to using unsigned numbers is things like forgetting 2u-3uis a positive number.

正如其他人所说,在处理单个位时,您确实应该使用无符号类型。在进行模运算时也是如此。如果您使用有符号类型,您就会面临大量与符号相关的错误。OTOH,几乎你使用无符号数字的唯一错误就是忘记2u-3u是一个正数。

(do be careful about mixing signed and unsigned numbers together: there are a lot of subtleties involved in that too)

(一定要小心混合有符号和无符号数字:这也涉及很多微妙之处)