web-dev-qa-db-ja.com

Cの決定的なCRC

CRCは非常に広く使用されているため、CでCRC実装を見つけるのに苦労していることに驚いています。

「全員」が使用するCの「決定的な」CRC計算スニペット/アルゴリズムはありますか?または:誰かが保証できる優れたCRC実装はありますか?特にCRC8とCRC16の実装を探しています。

考えてみると、私の状況は少し型破りかもしれません。私はLinux用のCコードを書いており、コードは最終的にマイクロコントローラーに移植されるはずです。一部のマイクロコントローラーAPIにはCRC実装が付属しているようです。いずれにせよ、私は一般的なソフトウェアの実装を探しています(CRCは元々ハードウェアで実装されることを意図していると読みました)。

17
oyvind

いいえ。CRCは多項式に基づく一連のアルゴリズムを表すため、「明確なCRC」はありません。通常、サイズに基づいてさまざまな[あいまい]共通名が付けられます(CRC-8、CRC-32など)。残念ながら、ほとんどのサイズにはいくつかの異なるバージョンがあります。

Wikipediaの Cyclic Redundancy Check エントリには一般的なバリアントがいくつかリストされていますが、正しいチェックサム指定されたドメインを使用する必要があります。使用しない場合、互換性がなくなります。 (これがどれほど混乱する可能性があるかについては、マイクの回答に対する私のコメントを参照してください!)

とにかく、適切な実装を選択してそれを使用してください-オンラインで見つけることができる例が不足することはありません。適切な実装を提供するライブラリがある場合は、必ずそれを使用してください。ただし、このための「標準」Cライブラリはありません。

ここにいくつかのリソースがあります:

15
user166390

CでCRC実装を見つけるのは難しくありません。CRC-32の比較的洗練された実装は zlib で見つけることができます。

以下は、いくつかの 16ビット および 8ビットCRC の定義です。これらは、この 優れたCRCの紹介 の規則を使用しています。

CRC-8の簡単な実装を次に示します。

// 8-bit CRC using the polynomial x^8+x^6+x^3+x^2+1, 0x14D.
// Chosen based on Koopman, et al. (0xA6 in his notation = 0x14D >> 1):
// http://www.ece.cmu.edu/~koopman/roses/dsn04/koopman04_crc_poly_embedded.pdf
//
// This implementation is reflected, processing the least-significant bit of the
// input first, has an initial CRC register value of 0xff, and exclusive-or's
// the final register value with 0xff. As a result the CRC of an empty string,
// and therefore the initial CRC value, is zero.
//
// The standard description of this CRC is:
// width=8 poly=0x4d init=0xff refin=true refout=true xorout=0xff check=0xd8
// name="CRC-8/KOOP"

static unsigned char const crc8_table[] = {
    0xea, 0xd4, 0x96, 0xa8, 0x12, 0x2c, 0x6e, 0x50, 0x7f, 0x41, 0x03, 0x3d,
    0x87, 0xb9, 0xfb, 0xc5, 0xa5, 0x9b, 0xd9, 0xe7, 0x5d, 0x63, 0x21, 0x1f,
    0x30, 0x0e, 0x4c, 0x72, 0xc8, 0xf6, 0xb4, 0x8a, 0x74, 0x4a, 0x08, 0x36,
    0x8c, 0xb2, 0xf0, 0xce, 0xe1, 0xdf, 0x9d, 0xa3, 0x19, 0x27, 0x65, 0x5b,
    0x3b, 0x05, 0x47, 0x79, 0xc3, 0xfd, 0xbf, 0x81, 0xae, 0x90, 0xd2, 0xec,
    0x56, 0x68, 0x2a, 0x14, 0xb3, 0x8d, 0xcf, 0xf1, 0x4b, 0x75, 0x37, 0x09,
    0x26, 0x18, 0x5a, 0x64, 0xde, 0xe0, 0xa2, 0x9c, 0xfc, 0xc2, 0x80, 0xbe,
    0x04, 0x3a, 0x78, 0x46, 0x69, 0x57, 0x15, 0x2b, 0x91, 0xaf, 0xed, 0xd3,
    0x2d, 0x13, 0x51, 0x6f, 0xd5, 0xeb, 0xa9, 0x97, 0xb8, 0x86, 0xc4, 0xfa,
    0x40, 0x7e, 0x3c, 0x02, 0x62, 0x5c, 0x1e, 0x20, 0x9a, 0xa4, 0xe6, 0xd8,
    0xf7, 0xc9, 0x8b, 0xb5, 0x0f, 0x31, 0x73, 0x4d, 0x58, 0x66, 0x24, 0x1a,
    0xa0, 0x9e, 0xdc, 0xe2, 0xcd, 0xf3, 0xb1, 0x8f, 0x35, 0x0b, 0x49, 0x77,
    0x17, 0x29, 0x6b, 0x55, 0xef, 0xd1, 0x93, 0xad, 0x82, 0xbc, 0xfe, 0xc0,
    0x7a, 0x44, 0x06, 0x38, 0xc6, 0xf8, 0xba, 0x84, 0x3e, 0x00, 0x42, 0x7c,
    0x53, 0x6d, 0x2f, 0x11, 0xab, 0x95, 0xd7, 0xe9, 0x89, 0xb7, 0xf5, 0xcb,
    0x71, 0x4f, 0x0d, 0x33, 0x1c, 0x22, 0x60, 0x5e, 0xe4, 0xda, 0x98, 0xa6,
    0x01, 0x3f, 0x7d, 0x43, 0xf9, 0xc7, 0x85, 0xbb, 0x94, 0xaa, 0xe8, 0xd6,
    0x6c, 0x52, 0x10, 0x2e, 0x4e, 0x70, 0x32, 0x0c, 0xb6, 0x88, 0xca, 0xf4,
    0xdb, 0xe5, 0xa7, 0x99, 0x23, 0x1d, 0x5f, 0x61, 0x9f, 0xa1, 0xe3, 0xdd,
    0x67, 0x59, 0x1b, 0x25, 0x0a, 0x34, 0x76, 0x48, 0xf2, 0xcc, 0x8e, 0xb0,
    0xd0, 0xee, 0xac, 0x92, 0x28, 0x16, 0x54, 0x6a, 0x45, 0x7b, 0x39, 0x07,
    0xbd, 0x83, 0xc1, 0xff};

#include <stddef.h>

// Return the CRC-8 of data[0..len-1] applied to the seed crc. This permits the
// calculation of a CRC a chunk at a time, using the previously returned value
// for the next seed. If data is NULL, then return the initial seed. See the
// test code for an example of the proper usage.
unsigned crc8(unsigned crc, unsigned char const *data, size_t len)
{
    if (data == NULL)
        return 0;
    crc &= 0xff;
    unsigned char const *end = data + len;
    while (data < end)
        crc = crc8_table[crc ^ *data++];
    return crc;
}

// crc8_slow() is an equivalent bit-wise implementation of crc8() that does not
// need a table, and which can be used to generate crc8_table[]. Entry k in the
// table is the CRC-8 of the single byte k, with an initial crc value of zero.
// 0xb2 is the bit reflection of 0x4d, the polynomial coefficients below x^8.
unsigned crc8_slow(unsigned crc, unsigned char const *data, size_t len)
{
    if (data == NULL)
        return 0;
    crc = ~crc & 0xff;
    while (len--) {
        crc ^= *data++;
        for (unsigned k = 0; k < 8; k++)
            crc = crc & 1 ? (crc >> 1) ^ 0xb2 : crc >> 1;
    }
    return crc ^ 0xff;
}

#ifdef TEST
#include <stdio.h>
#define CHUNK 16384

int main(void) {
    unsigned char buf[CHUNK];
    unsigned crc = crc8(0, NULL, 0);
    size_t len;
    do {
        len = fread(buf, 1, CHUNK, stdin);
        crc = crc8(crc, buf, len);
    } while (len == CHUNK);
    printf("%#02x\n", crc);
    return 0;
}
#endif
29
Mark Adler

CRC-8またはCRC-16については不明ですが、CRC-32コードの例が RFC 1952 にあります。このRFCは、セクション8.1.1.6でCRC-16について説明している V.42 標準も参照しています。

RFC 1952にも次のように記載されています。

        If FHCRC is set, a CRC16 for the gzip header is present,
        immediately before the compressed data. The CRC16 consists
        of the two least significant bytes of the CRC32 for all
        bytes of the gzip header up to and not including the CRC16.
        [The FHCRC bit was never set by versions of gzip up to
        1.2.4, even though it was documented with a different
        meaning in gzip 1.2.4.]

ですから、あなたのCRC-16とCRC-32は潜在的にあります。 (CRC-32の最下位2バイトを使用するだけです。)

2
mpontillo

CRCの実装に使用されるさまざまなアルゴリズムがいくつかあります。多項式除算を行う素朴なものがあります。

ここ は、一般的な32ビットCRC計算用のCのさまざまなアルゴリズムへのリンクです。著者はまたいくつかの速度の比較を与えます。

Koopman には、さまざまなCRCのパフォーマンスを提供するWebサイトと、特定のパケット長に最適なCRCのガイドがあります。

1
Flip