• ベストアンサー

CRCの計算方法について

色々なサイトを参考にして、自分なりにCRC-ITU-TでCRCを計算する関数を作成しました。 いまいち理解が浅く、そのCRCの値が正しいのか判断できずに困っています。 以下にソースを載せます。 アドバイスを、どうかよろしくお願いします。 unsigned short Crc(unsigned char *Data, unsigned long num) {   unsigned short vCrc;    //CRCを計算する変数   unsigned char vData;   unsigned long i;   int j;   vCrc = 0;   vData = 0;   //初期化   for(i = 0; i <= num; i++){     vData = *(Data+i);   //1byte読み込み     for(j = 0; j < 8; j++){       //CRC計算変数がシフトで桁あふれする場合       if((vCrc & 0x8000) != 0){         vCrc = vCrc << 1;   //1bitシフト         vCrc = vCrc ^ 0x1021;  //多項式とXOR       }       else{         vCrc = vCrc << 1;       }       if((vData & 0x80) != 0){         vData = vData << 1;   //データ変数1bitシフト                 vCrc = vCrc ^ 0x0001;  //CRC計算変数に1をXOR       }       else{         vData = vData << 1;       }     }   }   return(vCrc); }

質問者が選んだベストアンサー

  • ベストアンサー
  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.2

そうなんですか^^ 失礼しました。以下のコードを実行すると boost のライブラリで計算したもの、Ru-LaLaさんのコードで計算したもの、サンプル実装で計算したものを比較すると、Ru-LaLaさんので計算したものだけ値が違うので、Ru-LaLaさんのコードが間違ってる可能性があるような気がします^^; サンプルコードは、  http://page.freett.com/seaside/vip/crc/ProgramC1.htm から取りました。サンプルコードをパクってしまえばいいのでは?(笑) ==== #include <iostream> #include <boost/crc.hpp> unsigned short ProgCrc1(unsigned char* Data, unsigned long StartAdr, unsigned long StopAdr) { unsigned short vCRC; /*CRCを計算する変数*/ unsigned char vData; /*CRC計算時に1データ読み込む変数*/ /*初期化*/ vCRC = 0; vData = 0; /*CRC書き込み位置の初期化*/ *(Data + StopAdr + 1) = 0; *(Data + StopAdr + 2) = 0; /*CRC-ITU-Tの計算*/ for(unsigned long Loop1=StartAdr; Loop1<=StopAdr+2; Loop1++) /*CRC書き込み位置までループ*/ { vData = *(Data + Loop1); /*1Byte読みこみ*/ /*CRC1Byte計算*/ for(char Loop2=0; Loop2<8; Loop2++) {/*CRC計算変数がシフトで桁あふれするか確認*/ if((vCRC & 0x8000) != 0) /*桁あふれ有り*/ { vCRC = vCRC << 1; /*CRC計算変数1Bitシフト*/ vCRC = vCRC ^ 0x1021; /*生成多項式のXOR*/ } else /*桁あふれ無し*/ { vCRC = vCRC << 1; /*CRC計算変数1Bitシフト*/ } /*データ変数がシフトで桁あふれするか確認*/ if((vData & 0x80) != 0) /*桁あふれ有り*/ { vData = vData << 1; /*データ変数1Bitシフト*/ vCRC = vCRC ^ 0x0001; /*CRC計算変数に1XOR*/ } else /*桁あふれ無し*/ { vData = vData << 1; /*データ変数1Bitシフト*/ } } } *(Data + StopAdr + 2) = (unsigned char)(vCRC & 0x00ff); /*CRCの下位書き込み*/ *(Data + StopAdr + 1) = (unsigned char)((vCRC >> 8) & 0x00ff); /*CRCの上位書き込み*/ return(vCRC); } unsigned short Crc(unsigned char *Data, unsigned long num) { unsigned short vCrc; //CRCを計算する変数 unsigned char vData; unsigned long i; int j; vCrc = 0; vData = 0; //初期化 for(i = 0; i <= num; i++){ vData = *(Data+i); //1byte読み込み for(j = 0; j < 8; j++){ //CRC計算変数がシフトで桁あふれする場合 if((vCrc & 0x8000) != 0){ vCrc = vCrc << 1; //1bitシフト vCrc = vCrc ^ 0x1021; //多項式とXOR } else{ vCrc = vCrc << 1; } if((vData & 0x80) != 0){ vData = vData << 1; //データ変数1bitシフト vCrc = vCrc ^ 0x0001; //CRC計算変数に1をXOR } else{ vData = vData << 1; } } } return(vCrc); } unsigned short crc_itu_t(unsigned char *data, unsigned long num) { boost::crc_basic<16> calc(0x1021); calc.process_bytes(data, num); return static_cast<unsigned short>(calc.checksum()); } int main() { unsigned char data[6 + 2] = { 'a', 'b', 'c', 'd', 'e', 'f' }; std::cout << std::showbase << std::hex; std::cout << crc_itu_t(data, 6) << '\n'; std::cout << Crc(data, 6) << '\n'; std::cout << ProgCrc1(data, 0, 5) << '\n'; std::cout << static_cast<int>(data[6]) << '\n'; std::cout << static_cast<int>(data[7]) << '\n'; } ==== ./a.exe 0x3afd 0x58e1 0x3afd 0x3a 0xfd

Ru-LaLa
質問者

お礼

親切にありがとうございます。 やっぱり間違っているんですね。 教えて頂いたURLをパクリつつ、もう少し頑張ってみます。

その他の回答 (6)

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.7

★昔買ったアルゴリズム事典より抜粋します。 サンプル: #include <limits.h> unsigned short crc( unsigned const char *pData, unsigned long lNum ) {  unsigned int crc16 = 0xFFFFU;  unsigned long i;  int j;    for ( i = 0 ; i < lNum ; i++ ){   crc16 ^= (unsigned int)pData[i] << (16 - CHAR_BIT);   for ( j = 0 ; j < CHAR_BIT ; j++ ){    if ( crc16 & 0x8000 ){     crc16 = (crc16 << 1) ^ 0x1021;    }    else{     crc16 <<= 1;    }   }  }  return (unsigned short)(~crc16); } その他: ・回答者 No.2 さんのリンクのソースでfor文の条件式が『Loop1<=StopAdr+2』となる理由が  良く分からないな?何で『StopAdr+2』に『+2』にしているの?不思議だ。どいう理由かな。  そもそも CRC-ITU-T って聞いた事が無い。CRC-CCITT なら聞いた事があります。  XOR している定数が 0x1021 だから多項式は x^16+x^12+x^5+x^0 となり CRC-CCITT だよな。  ネット検索したら『CRC-ITU-T』でヒットしたのでページを見たら多項式は同じだった。  http://page.freett.com/seaside/vip/crc/DocCRC.htm→『CRCの正体と種類』  もしかして『CRC-ITU-T』と『CRC-CCITT』は同じなのかな?→読んだら今は『ITU-T』だって。同じだ。 ・アルゴリズム事典では『if ( vData & 0x80 ){ … }』の処理はないね。  この質問のソースを見たときに『あれ?何か?変?』と思った箇所だ。  もう良く分からないのでこれまで。ギブアップ! ・以上。

Ru-LaLa
質問者

お礼

ありがとうございます。参考にします。

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.6

うーーん。。。Oh-Orange さんので試してみましたが、値がサンプルコードのものや boost のライブラリのものとは違いますね^^; どれが正しいのか読んでないのでわかりませんが、『あるものは使えばいい。壊れてないのに直すなよ(by ワインバーグ)』ってことで、サンプルコードをそのまま使うのがいいんじゃないでしょうか。。。

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.5

★最初に。 >for(i = 0; i <= num; i++){  ↑  for(i = 0; i < num; i++){  です。『<=』だと1バイト余分に計算しちゃいますよ。  『i』カウンタを使うよりはポインタを使ったら。 ・下に書き直したソースを貼り付けて置きます。 サンプル: unsigned short Crc( unsigned char *Data, unsigned long num ) {  unsigned short vCrc;  //CRCを計算する変数  unsigned char vData;  int i;    for ( vCrc = 0 ; num > 0 ; num-- ){   vData = *Data++;  //1byte読み込み      for ( i = 0 ; i < 8 ; i++ ){    vCrc <<= 1; //1bitシフト    vData <<= 1; //データ変数1bitシフト        //CRC計算変数がシフトで桁あふれする場合    if ( vCrc & 0x8000 ){     vCrc ^= 0x1021; //多項式とXOR    }    if ( vData & 0x80 ){     vCrc ^= 1; //CRC計算変数に1をXOR    }   }  }  return vCrc; } その他: ・次のリンクを元に CRC-CCITT を書き直すと左ローテートしないといけないみたいだよ。  http://www.wdic.org/w/WDIC/CRC→『CRC - 通信用語の基礎知識』 ・テーブルを用いた CRC16 のソースが Vector さんのところにあります。  下の『参考URL』もどうぞ。 ・以上。

参考URL:
http://www.vector.co.jp/soft/dos/hardware/se020402.html
Ru-LaLa
質問者

お礼

なるほど、まずはそこからおかしかったのですね。 ありがとうございます。

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.4

ていうか、コードが似てるので、パクりそこねたんですかね^^ そのまま使えばいいんじゃないでしょうか。。。

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.3

ん?ProgCrc1(data, 0, 5) で呼び出さないといけないのかな?すみません、Ru-LaLa さんのプログラムをきちんと読んでいないので^^; でも、  std::cout << ProgCrc1(data, 0, 5) << '\n'; としても、値が 0xcd50 になって、他ので計算した値とは違いました^^;

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.1

直接の回答ではないですが、特別なものでなければ、自分で作るより boost とかの CRC を使ったほうがいいんじゃないかと思います^^ http://boost.cppll.jp/HEAD/libs/crc/crc.html

Ru-LaLa
質問者

お礼

早い回答ありがとうございます。 すみません、私はC言語初心者でして。 参考のURL先の内容を理解できません。 本当に、ごめんなさい。

関連するQ&A