这个CRC实现有一个众所周知的名称吗?这个代码是用C编写的,但我认为这与BBC micro的磁带归档系统使用的CRC计算相同。但BBC的微文件并没有具体说明CRC的名称。我也找不到任何明显的匹配http://reveng.sourceforge.net/crc-catalogue/16.htm或https://en.wikipedia.org/wiki/Cyclic_redundancy_check
inline unsigned long crc_cycle(unsigned long crc)
{
if (crc & 32768)
return (((crc ^ 0x0810) & 32767) << 1) + 1;
else
return crc << 1;
}
unsigned long crc_update(unsigned long crc, const byte *start, const byte *end)
{
for (const byte* p = start; p < end; ++p)
{
crc ^= *p++ << 8;
for(int k = 0; k < 8; k++)
crc = crc_cycle(crc);
assert((crc & ~0xFFFF) == 0);
}
return crc;
}
unsigned long crc(const byte *start, const byte* end)
{
return crc_update(0, start, end);
}
英国广播公司《微型计算机高级用户指南》第348页也描述了这种校验和,但也没有给出名称。该页面上的代码是6502汇编:
LDA #0
STA H Initialise the CRC to zero
STA L
TAY Initialise the data pointer
.nbyt LDA H Work data into CRC
EOR data,Y
STA H
LDX #8 Perform polynomial recycling
.loop LDA H Loop is performed 8 times, once for bit
ROL A Test if a bit is being cycled out
BCC b7z
LDA H Yes, add it back in *~8~5
EOR #8
STA H
LDA L
EOR #&l0
STA L
.b7z ROL L Always, rotate whole CRC left one bit
ROL H
DEX
BNE loop Do once for each bit
INY Point to next data byte
CPY #lblk All done yet?
BNE nbyt
RTS All done- H=CRC Hi, L=CRC
多项式为0x10000+(0x810<<1(+1=0x1021,称为CRC16-CCITT。
然而,根据我在20世纪80年代和Wiki文章中回忆的内容,CRC16-CCITT是使用多项式0x11021为任何CRC命名的。除了多项式之外,CRC可以是左移(未反映(、右移(反映(,具有初始值,并且结果可以是互补的。在线计算器有相应的复选框:反映输入、反映输出、初始值、最终xor值。(输入和输出的反射不相同的情况很少见(。
该代码实现了一个左移CRC,初始值为0,没有最终的异或,假设没有像CRC_update这样的另一个函数不接受输入参数并将CRC初始化为某个特定值。
Mark Adler指出了代码中的错误,比如在循环中增加p两次。我也看不出断言的意义(crc&~0xffffff==0((~0xffff==0x…0000?(
问题中的C源代码出错。指向数据的指针无意中增加了两次,只对每隔一个字节计算CRC!此:
crc ^= *p++ << 8;
应该是这样的:
crc ^= *p << 8;
汇编程序代码中有一个字符在手册中出现错误,其中EOR #&l0
本应为EOR #&10
。
更正后,两个代码都计算CRC-16/XMODEM
(这里的另一个答案是将"CRC16-CCITT"称为具有该多项式的CRC家族,但reveng目录中的CRC-16/CCITT不会产生与问题中的代码相同的输出。虽然它们使用相同的多项式,但CRC-16/CCITT得到了反映,而代码中的CRC则没有。(