在 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 提供了很多 更好的数据损坏检测 - 但不能操纵。
我在为 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 提供了很多 更好的数据损坏检测 - 但不能操纵。