在 C 中写一个 8 位校验和

writing an 8 bit checksum in C

我在为 1 字节/8 位校验和编写算法时遇到问题。 显然,对于十进制值 255 的 8 位,最高有效位必须环绕。我认为我做得对。

这是代码...

#include <stdio.h>


int main(void)
{
    int check_sum = 0;              //checksum
    int lcheck_sum = 0;             //left checksum bits
    int rcheck_sum = 0;             //right checksum bits
    short int mask = 0x00FF;            // 16 bit mask

    //Create the frame - sequence number (S) and checksum 1 byte

    int c;
    //calculate the checksum
    for (c = 0; c < length; c++)
    {
        check_sum = (int)buf[c] + check_sum;
        printf("\n Check Sum %d ", check_sum);      //debug
    }

    printf("\nfinal Check Sum %d", check_sum);      //debug

    //Take checksum and make it a 8 bit checksum

    if (check_sum > 255)            //if greater than 8 bits then encode bits
    {

        lcheck_sum = check_sum;
        lcheck_sum >> 8;    //shift 8 bits to the right

        rcheck_sum = check_sum & mask;
        check_sum = lcheck_sum + rcheck_sum;
    }


    //Take the complement
    check_sum = ~check_sum;


    //Truncate - to get rid of the 8 bits to the right and keep the 8 LSB's
    check_sum = check_sum & mask;

    printf("\nTruncated and complemented final Check Sum %d\n",check_sum);
    return 0;
}

简短回答:你没有正确地做到这一点,即使 如果 算法会像你的代码所暗示的那样(这不太可能)。

标准警告:如果您的变量可能换行(未定义的行为)或您想要正确,请不要使用int -shift 潜在的负值(实现定义)。 OTOH,对于无符号类型,包装和移位行为由标准明确定义。

进一步注意:如果您需要特定的位大小,请使用 stdint.h 类型!内置标准类型保证(包括char)提供这样的。

通常8位缓冲区的8位校验和计算如下:

#include <stdint.h>

uint8_t chksum8(const unsigned char *buff, size_t len)
{
    unsigned int sum;       // nothing gained in using smaller types!
    for ( sum = 0 ; len != 0 ; len-- )
        sum += *(buff++);   // parenthesis not required!
    return (uint8_t)sum;
}

不清楚您对所有类型转换或转换做了什么; uint8_t 作为保证最小(无符号)类型,高位保证为 "cut off"。

只需将此代码与您的代码进行比较,您应该能够看到您的代码是否有效。

另请注意,没有 单一校验和算法。我没有在我的代码中反转结果,也没有像你那样折叠上下字节(后者很不常见,因为它没有增加更多的保护)。

因此,您必须验证要使用的算法。如果确实需要折叠 16 位结果的两个字节,请将 sum 更改为 uint16_t` 并按如下方式折叠字节:

uint16_t sum;
...
// replace return with:
while ( sum > 0xFFU )
    sum = (sum & 0xFFU) + ((sum >> 8) & 0xFFU);
return sum;

这里关心的是将 sum 的两个字节相加产生的任何溢出(循环也可以展开,因为溢出只能发生一次)。

有时,CRC 算法被称为 "checksum",但它们实际上是一个非常不同的野兽(从数学上讲,它们是二进制多项式除法的余数)并且需要更多的处理(在 运行-时间,或生成查找-table)。 OTOH,CRC 提供了很多 更好的数据损坏检测 - 但不能操纵