【问题标题】:CRC-15 giving wrong valuesCRC-15 给出错误值
【发布时间】:2017-04-14 22:32:24
【问题描述】:

我正在尝试在 c 中创建一个 CRC-15 检查,并且文件的每一行的输出都永远不正确。我正在尝试在每行旁边累积输出每行的 CRC。我使用:#define POLYNOMIAL 0xA053 作为除数,使用文本作为被除数。我需要将数字表示为 32 位无符号整数。我尝试打印出十六进制值以跟踪和翻转不同的班次。但是,我似乎无法弄清楚!我觉得这与我填充事物的方式有关。我的逻辑有问题吗?

CRC 将用四个十六进制数字表示,该序列将有四个前导 0。例如,它看起来像 0000xxxx,其中 x 是十六进制数字。我使用的多项式是 0xA053。

我考虑过使用一个临时变量,并在每次异或时每行执行 4 个 16 位的代码块,但是,我不太确定如何使用移位来完成此操作,所以我决定对上面的字母进行校验和行,然后对其进行异或以尝试计算 CRC 码。

我正在使用以下输入和填充测试我的代码。直到字符串的长度为 504,因为这是填充字符需要通过给定的要求: “这就是教训:决不屈服,决不屈服,决不,决不,决不,决不——无论大小,大或小——决不屈服,除非是对荣誉和理智的信念。决不屈服于武力;永远不要屈服于敌人看似压倒性的力量。”

前 64 个字符行的 CRC(“这是教训:永不放弃,永不放弃,永不,永不,)应该是 000015fa,我得到 bfe6ec00。

我的逻辑:

  • 在 CRCCalculation 中,我将每个字符添加到一个 32 位无符号整数,然后在 64(一行的长度)之后将其发送到 XOR 函数中。

  • 如果最高位不是1,我将数字左移一位 导致 0 填充右侧并再次循环。

  • 如果最高位为 1,则将被除数与除数异或,然后将被除数左移。

  • 所有计算完成后,我将左移四位的被除数(前面加四个零)返回给计算函数

  • 将结果添加到结果的总和中

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#define POLYNOMIAL 0xA053
void crcCalculation(char *text, int length)
{
    int i;
    uint32_t dividend = atoi(text);
    uint32_t  result;
    uint32_t sumText = 0;

    // Calculate CRC
    printf("\nCRC 15 calculation progress:\n");

    i = length;

    // padding
    if(i < 504)
        {
            for(; i!=504; i++)
                {
                    //  printf("i is %d\n", i);
                    text[i] = '.';
                }
        }
    // Try calculating by first line of crc by summing the values then calcuating, then add in the next line
    for (i = 0; i < 504; i++)
        {
            if(i%64 == 0 && i != 0)
                {
                    result = XOR(POLYNOMIAL, sumText);
                    printf(" - %x\n",result);


                }
            sumText +=(uint32_t)text[i];
            printf("%c", text[i]);
        }

    printf("\n\nCRC15 result : %x\n", result);
}

uint32_t XOR(uint32_t divisor, uint32_t dividend)
{
    uint32_t divRemainder = dividend;
    uint32_t currentBit;
    // Note: 4 16 bit chunks

    for(currentBit = 32; currentBit > 0; --currentBit)
        {
            // if topbit is 1
            if(divRemainder & 0x80)
                {
                    //divRemainder = (divRemainder << 1) ^ divisor;
                    divRemainder ^= divisor;
                    printf("%x %x\n", divRemainder, divisor);
                }
            //  else
            //  divisor = divisor >> 1;
            divRemainder = (divRemainder << 1);
        }
    //return divRemainder;  , have tried shifting to right and left, want to add 4 zeros to front so >>
    //return divRemainder >> 4;
    return divRemainder >> 4;
}

【问题讨论】:

  • 你为什么要总结每64个字符的文本?这无论如何都不是 CRC。
  • 我正在尝试累计获取每行的 CRC 总数,我假设这个求和和 XORing 会得到该行的位,然后我会去添加下一行,然后得到这些位...我正在考虑将文本数组发送到 XOR 函数并创建一个临时变量,该变量会一点一点地移动这些位,但是,我不太确定如何将这些位移动到临时数组中。例如,如果我将一行的 4 个 16 位块发送到 XOR 并根据需要移入另一位,直到数组为空并使用它来 XOR 事情,这是否比求和更 CRC?
  • 为什么不计算 16 位 CRC?一次处理一个完整字节比处理部分字节要容易得多/
  • 发布的代码有几个“神奇”数字:504 和 64。“神奇”数字是没有依据的数字。 “神奇”数字使代码更难理解、调试等。建议使用enum 语句或#define 语句为这些“神奇”数字赋予有意义的名称,然后在整个代码中使用这些有意义的名称。跨度>
  • @user3629249 讲师要求 32 位。我没有及时完成。但是,我走在正确的轨道上,并且仍在努力!我肯定会尝试用 16 位来解决它,因为我只是为了好玩:)。

标签: c return checksum crc


【解决方案1】:

我看到的第一个问题是top bit check,应该是:

        if(divRemainder & 0x8000)

问题没有说明 CRC 是否被位反映(异或数据到 CRC 的低位,循环右移)或没有(异或数据到 CRC 的高位,循环左移),所以我无法为其余代码提供帮助。

该问题没有说明 CRC 的初始值(0x0000 或 0x7fff),或者 CRC 是否后补。

常规 CRC 的逻辑是:

  • xor 一个字节的数据到 CRC(高位或低位)
  • 循环 CRC 8 次(或进行表查找)

在为整个消息生成 CRC 后,可以将 CRC 附加到消息中。如果为带有附加 CRC 的消息生成 CRC 并且没有错误,则 CRC 将为零(如果 CRC 后补,则为常数值)。

【讨论】:

  • 我不太清楚你所说的 CRC 的初始值是什么意思,我设置了 result = 0 然后我将异或值相加到结果中。至于反映,我正在更新帖子,希望能回答这个问题。
【解决方案2】:

这是一个典型的 CRC16,摘自:&lt;www8.cs.umu.se/~isak/snippets/crc-16.c&gt;

#define POLY 0x8408
/*
//                                      16   12   5
// this is the CCITT CRC 16 polynomial X  + X  + X  + 1.
// This works out to be 0x1021, but the way the algorithm works
// lets us use 0x8408 (the reverse of the bit pattern).  The high
// bit is always assumed to be set, thus we only use 16 bits to
// represent the 17 bit value.
*/

unsigned short crc16(char *data_p, unsigned short length)
{
      unsigned char i;
      unsigned int data;
      unsigned int crc = 0xffff;

      if (length == 0)
            return (~crc);

      do
      {
            for (i=0, data=(unsigned int)0xff & *data_p++;
                 i < 8; 
                 i++, data >>= 1)
            {
                  if ((crc & 0x0001) ^ (data & 0x0001))
                        crc = (crc >> 1) ^ POLY;
                  else  crc >>= 1;
            }
      } while (--length);

      crc = ~crc;
      data = crc;
      crc = (crc << 8) | (data >> 8 & 0xff);

      return (crc);
}

由于您要计算 CRC15 而不是 CRC16,因此逻辑会更复杂,因为无法处理整个字节,因此需要进行大量位移和 AND 运算来提取所需的 15 位。

注意:OP没有提到CRC的初始值是0x0000还是0x7FFF,也没有提到结果是否需要补码,也没有提到某些其他标准,所以这个贴出来的代码只能作为参考。

【讨论】:

  • 需要注意的是,预先计算一个 CRC 表可以使这段代码更快,因为可以消除内部循环和位移。
  • 谢谢!我会调查的。
猜你喜欢
  • 1970-01-01
  • 2014-09-10
  • 2012-01-13
  • 2019-11-11
  • 2012-10-20
  • 2014-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多