CRCの検定コードが同じになる問題

このQ&Aのポイント
  • C言語の初級者が巡回符号方式(CRC)を使用した場合、伝送誤り検出のための検定コードを算出する課題に取り組んでいます。
  • しかし、プログラムを実行しても、検定コードがどの文字の場合でも同じになり、和も常に1530になってしまいます。
  • 問題の鍵は、検定コードが255(16進数ではFF)になることであり、これを解決するために何かアイデアはありますか?
回答を見る
  • ベストアンサー

CRCの検定コードがどの文字でも同じになった!?

C言語の初級者が質問します。 講義の課題で、「伝送誤り検出方式として巡回符号方式(CRC:Cyclic Redundancy Check)を使用した場合、送り側でアルファベット6文字の適当な単語を1文字ずつ入力した場合の検定コードを算出しなさい。生成多項式はCRC-16-CCITT(Xの16乗)+(Xの12乗)+(Xの5乗)+1を使用し、検定コードは2byteとする。 この課題に対し、一文字ずつ、検定コードを求めて合計6個の和を出して16進数で表現しようと考え、以下のプログラムを作りました。#include <stdio.h> #include <string.h> #include <stdlib.h> int main () { int t,s,i,m; int l; int flag; int crcReg[10]; // crcRegは一文字ごとのCRCの計算途中過程 res[]は一文字ごとのCRCの最終結果 char inData[6]; //文字列入力 int jyuroku[6]; int crcmax; printf("文字入力(6文字まで):"); gets(inData); // l=strlen(inData); for(i = 0;i < l; i++) { printf("%d番目は16進数で%X\n",i+1,inData[i]); // } printf("各文字の16進asciiは(0x必要か?)"); for(m = 0;m <l;m++) { printf("%d番目のascii:",m+1); scanf("%X", &jyuroku[m]); // } //**********************************(後半)********************************************** for(s=0;s < l; s++) {//文字の数だけ繰り返し crcReg[s]=0xFFFF; //CRCの初期値はどの文字の場合でも同じ printf("%d 番目の16進ascii:%X\n",s+1,jyuroku[s]); // for (t = 0;t < 8; t++) { //入力する16進数は8ビット=1バイト ゆえ8回繰り返し flag = (crcReg[s] ^ jyuroku[s] & 0x01); // 生成多項式をかけるかどうかの判定の前段階 crcReg[s] = crcReg[s] >> 1; //CRCの計算過程を1ビット右にシフト if (flag == 0x01) { //最下位ビットflagが1の時の処理 crcReg[s] = (crcReg[s] ^ 0x8408); //生成多項式は10進数で } else if (flag == 0x00) { } jyuroku[s] = jyuroku[s] >> 1; // asciiコードも1 ビットシフト } printf("CRCの結果は%X\n",crcReg[s]); // } crcmax = crcReg[0]+crcReg[1]+crcReg[2]+crcReg[3]+crcReg[4]+crcReg[5]; printf("\n kekka:%d",crcmax); // return 0; // } しかし、こうするとcrcReg[s](検定コード)がどの文字の場合でも同じ255(16進数ではFF)になって、6文字の単語は常に和が1530になってしまいます。255=16の2乗-1であることが問題解決の鍵だと思うのですが、何か問題点わかりますか?

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

  • ベストアンサー
回答No.2

うまくいきません。だけではなく、 必ず同じ結果になるということに 着目したのは、まず、OKとしま しょう。 「結果」というのは、直接的には、 crcReg[] の値です。 まず、crcReg[] の値を変化させて いる(または設定している)箇所を 全て抜き出します。 1) crcReg[s]=0xFFFF; 2) crcReg[s] = crcReg[s] >> 1; 3) crcReg[s] = (crcReg[s] ^ 0x8408); よく見ると、1) は、初期設定。 2) は、for(t = 0; t < 8; t++) の ループで毎回実行されますから、 トータルで、8ビット右シフトが発生し ここで、crcReg[] は、0x00ff に なっていることがわかります。 そうすると、3) は、「一度も実行 されていない」ことが推定できます。 ここまでが第一段階。 次に行きます。 3) が一度も実行されていないというこ とは、これを実行するための条件が 決して満足されないということです。 つまり、 if (flag == 0x01) が成立しない。 つまり、 flag = (crcReg[s] ^ jyuroku[s] & 0x01); が 0x01 にならない。 ということがわかります。 結論から言えば、ここが今回問題点です。 & と ^ は演算子の優先順位が異なります。 (& の優先順位が高い) 従って、この式は、意図しない順序で計算 されます。 この結果、flag の上位桁には、crcReg[] の (そもそも、0xffff で初期化された)値 がそのまま反映されてしまいます。 この結果、flga が 0x01 になることはない というのが今回の結果になります。 そうすれば、 flag = ((crcReg[s] ^ jyuroku[s]) & 0x01); とすれば少なくとも、「同じ結果」にはなら ないことがわかると思います。

その他の回答 (1)

回答No.1

参考にしてください static Word crctable[256]; void MakeCrc(void) {   Word i;   Word j;   Word r;   for (i = 0; i < 256; i++) {     r = i;     for (j = 0; j < 8; j++)       if (r & 1)         r = (r >> 1) ^ 0x8408u;       else         r >>= 1;     crctable[i] = r;   } } Word GetCrcN(Byte *s, int len) {   Word r;   r = 0xFFFFu;   while (len--) {     r = (r >> 8) ^ crctable[(Byte)r ^ *s++];   }   return (r ^ 0xFFFFu); }

4253187b
質問者

お礼

とりあえずありがとうございます

関連するQ&A

  • CRC16コード作成プログラムについて

    お世話なります。 PCと対象機械との通信を行おうと思っております。 内容としてCRC16のコードを使って、日時設定をPC→対象機器へ行いたいです。 CRC16の生成プログラムをいろいろ調べてみたところ、 今、自分のスキルでなんとかわかりそうなCRC16のソースが次の通りでした。 (行列の計算ぐらいならC言語で作れる程度です。。。) unsigned short crc_cal(unsigned short lng, unsigned char *str) { unsigned short crc, i, j, t; crc = 0xffff; for (i = 0; i < lng ; i++) { crc ^= (unsigned short) str[i]; for (j = 1; j <= 8; j++) { if (crc & 1) { // carry bit on crc = crc >> 1; crc ^= 0xa001; } else { // carry bit off crc = crc >> 1; } } } return crc; } “0C0C0C0C0C0C”と入力したら、CRCコードが算出されるプログラムを作りたく、 入力部分を作成してみたのですが・・・ int main(void) { unsigned short i,j, t; unsigned char str[256]; unsigned char str0; unsigned short crc; int k=0; printf("Please input key (HEX)\n"); for(k=0; k < 256; k++) { scanf("%c",&str0); // 文字列標準入力 if( str0=='\n') // Enterが押されたときの実行 { str[k]='\0'; // 文末にNULL文字 break; // for文のループ終了 } else { str[k]=str0; // NULLでなければ入力された文字を代入 } } crc = crc_cal(k,str); printf("crc=%X\n", crc); return 0; } 文字列を分解して・・・やるんだろうなってまではなんとなくわかるのですが、 どのようにしたらよいでしょうか。。。 ご教授よろしくお願いします。

  • CRC(チェックサム)のASCIIコードについて

    現在装置を外部PCから操作させる設定の一覧を作成しています。 メーカーからの指定は、設定したい数値を(16進数) 40 NN NN NN CRC  をASCIIコードで入力するように指定されています。 例えば、50に設定したい場合は @050* (40 30 35 30 2A) と入力します。 ここで、CRCがASCIIの制御文字(00~1F)に該当してしまう場合、どのように CRCを設定するか分からずにいます。 このような場合は、どのような設定をするものなのでしょうか?

  • バイナリ表記を表示するコードが分かりません(C言語)

    下記のプログラムはビットごとのANDを使って、 キーボードから入力された文字のASCIIコードをバイナリ表記で表示します。 #include <stdio.h> #include <conio.h> int main(void) { char ch; int i; printf("文字を入力してください: "); ch = getche(); printf("\n"); /* バイナリ表記を表示する */ for(i=128; i>0; i=i/2) if(i & ch) printf("1 "); else printf("0 "); return 0; } 【質問】 「バイナリ表記を表示する」部分のコードで、 1バイト(8bit)の最上位ビットは128(2の7乗)の重みがあり、それを初期値に与えて、 「i=i/2」で64,32,16,8,4,2,1と重みが下がっていくというのは分かりますが、 if(i & ch) で、どうして「i & ch」とすることで、バイナリ表記が表示できるのでしょうか? どなたか教えて頂けないでしょうか?お願いします。

  • C++で16進数の文字コードから文字を表示する

    現在C++を習得しようとテキストを使い練習中なのですがC++で16進数の文字コードから文字を表示するプログラムを作れという問題で一通りできる様にはなったのですが リビルドしたときは正常終了するのですがビルドの段階でデバッグエラーが発生してしまいます。 #include <stdio.h> int main(void) { char suuji; printf("2桁の16進数('41'~'49'、'50'~'59')を入力して下さい:\n"); scanf("%02x",&suuji); printf("文字コード「%02x」の文字は「%c」です。\n",suuji,suuji); return 0; } エラーの内容は画像を添付いたしました。 原因が何なのかが分からなくて困っております。 もしよろしければご指摘お願いします!

  • 大文字を小文字に、小文字を大文字にするプログラム

    問題は、 ファイルにあるアルファベットの大文字を小文字に変換し、小文字は大文字に変換して、ファイルに保存するプログラムを作りなさい というものです。 色々考えて、 #include <stdio.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <stdlib.h> #include <unistd.h> #include <ctype.h> int main(int argc,char **argv){ int fd,flag1,flag2; int i,n; char buffer[512],x; fd = open(argv[1],O_RDWR); if(fd == -1) perror("open"); while((n = read(fd,buffer,sizeof(buffer)))>0){ x = buffer[i]; flag1 = islower(x); flag2 = isupper(x); for(i=0;i<n;++i) if(flag1 == 1){ buffer[i] = toupper(buffer[i]); }else if(flag2 == 1){ buffer[i] = tolower(buffer[i]); } write(fd,buffer,n); } close(fd); exit(0); } のようなプログラムを考えましたが、うまくいきません。 toupperのような関数を使ったのは初めてなのでよく使い方が分からずこのようなプログラムになってしまいました。 どうか正しく動くようなプログラムを教えてください。お願いします。

  • 文字列中の空白部の読み込みの方法を教えてくださいm(_ _)m

    いつもお世話になっています!!キーボードから以下のような文字列を読み込み、大文字のみをカウントするプログラムを作りたいのですが、空白部になると次の文字を判定せずにプログラムが停止してしまいます。。。どなたかアドバイスをお願いしますm(_ _)m ○文字列 My name is Marly. ○プログラムソース #include<stdio.h> #include<stdlib.h> #include<string.h> int main(void){ char *s; int i,j=0,m; s=(char*)malloc(sizeof(char)); printf("please iput sentens\n"); scanf("%s",s); m=strlen(s); for(i=0;i<m;i++){ if( 0x41 <= s[i] && s[i] <= 0x5A) j++; } printf("%d",j); free(s); return(0); }

  • C言語 この問題が分かりません!教えてください!

    1.文字をキーボードから入力し、該当するASCIIコードを8進数、10進数、 16進数で出力する。 (printf ,scanfを使用) 2.文字コード(ASCII)を10進数で入力し、そのコードにあてはまる文字を出力。(printf scanf) 1と2は問題は全く別です。 よろしくお願いします。

  • 文字型配列について質問です。

    「文字型配列にsを宣言し、初期値に[yamada tagosaku ]をセットする。この文字列を表示する。次にキーボードから入力した1文字が何個含まれているかの個数を表示する。キーボードから入力する1文字は文字型変数mに、個数をカウントする変数はctにする。流れ図に従ってプログラムを作れ。」 という問題なのですが、BcPadでエラーが出てしまいます。 困っているので、訂正箇所を教えていただければ幸いです。 流れ図はhttp://imepita.jp/20080527/718540です。 int i,ct=0; char s[20]="yamada tagosaku ",m; printf("%s\n",s); printf("探す1文字 => "); scanf("%s",m);      i=0; while(s[i]!=NULL){ if(s[i]==m) ct++; i++; } printf("%s は%d個あります。\n",m,ct); }

  • C言語

    ストップウォッチの一時停止の機能をもつプログラムを作成しているのですが、上手く動作しません。 (一時停止し、再開してもその状態から再開できない状態) #include <windows.h> #include <mmsystem.h> #include <stdio.h> #include <conio.h> #pragma comment(lib, "winmm.lib") int main(void) { int command;//キーボード入力の文字判別用変数 int quit_flag = 1;//プログラム終了フラグ 0で停止 int c_flag = 0;//カウント状態取得用フラグ 1:カウント中,0:停止中 int h,m,s,ms;//左から,時間,分,秒,ミリ秒 int b,c,d,e; int a; int f,g,i; DWORD start,cur; printf("使い方:小文字の's'でカウントスタート.カウント中,小文字の's'で停止.次の's'でまた0からスタート\n"); printf("使い方:どんな状態でも小文字の'r'でカウントリセットして停止\n"); printf("使い方:qでプログラム終了\n\n"); printf("使い方:tを押すと一時停止.一時停止中,tで計測再開\n"); h=m=s=ms=0; b=c=d=e=0; while(quit_flag != 0)//quit_flagが0以外ならループ { while(!_kbhit())//何かキーが押されるまでループ { if(c_flag != 0)//c_flagが0以外であればカウント中ということ. { h=m=s=ms = timeGetTime() - start; b=h/3600000; c=(m/60000)%60; d=(s/1000)%60; e=ms%1000; cur=timeGetTime(); ms=(cur-g); f=ms; } printf("%02d:%02d:%02d:%03d\r",b,c,d,e); } command=_getch();//ループを抜けるために押されたキーの内容をcommandに代入. if(command=='s' && c_flag == 0) { printf("\n計測開始\n"); c_flag = 1; start = timeGetTime() ; h=m=s=ms=0; } else if(command=='t' && c_flag != 0) { printf("\n一時停止\n"); c_flag = 0; a=c_flag; //計測開始時にtを押すとバグが発生するため } else if(command=='t' && a==0) { printf("\n計測再開\n"); c_flag = 1; f=timeGetTime(); } else if(command=='s') { printf("\n計測中止\n"); c_flag = 0; } else if(command=='r') { printf("\nカウンタリセット,停止\n"); c_flag = 0; h=m=s=ms=0; } else if(command=='q') { printf("\n終了\n"); quit_flag = 0; } else if(command=='l' && c_flag==1) { c_flag=0; printf("\nラップ\n"); printf("%02d:%02d:%02d:%03d\n",h/3600000,(m/60000)%60,(s/1000)%60,ms%1000); c_flag=1; } } return 0; } 差分をとれば良いと聞いたのですが、どのようにとれば良いか全く分からなくて困っています。 ソースコードを修正または適宣追加をしてくだされば幸いです。

  • 文字の並べ替えについて質問

    以下のような標準入力したアルファベットの文字列(jgoaihoghohgo...みたいな)を昇順に並べ替えるプログラムを作成して思ったのですが、各文字の比較ってやっぱりアスキーコードの数字を比較しているのでしょうか? だとするとif(s[i]<s[j])の部分で少し疑問を感じました。 if(s[i]>s[j])ではないのでしょうか?こうでないとs[i]にaがs[j]にbが格納されているときに並べ替えが起きてしまうような気がするのです。 基本的なことのようですがお願いしますm(__)m あとプログラムに関して不備を感じましたら訂正のアドバイスをお願いします。 #include<stdio.h> #include<string.h> int main(void){ char s[BUFSIZ]; char s2[BUFSIZ]; int i,j,m; printf("input sentense.\n"); scanf("%s",s); m=strlen(s); for(i=0;i<m;i++){ for(j=0;j<m;j++){ if(s[i]<s[j]){ s2[10]=s[i]; s[i]=s[j]; s[j]=s2[10]; } } } printf("%s",s); return(0); }