プロが教えるわが家の防犯対策術!

GPS受信機で出力されるデータのチェックサムをC言語で算出しようと思いましたが、
下記のように$から*の文字間($*は含めず、数字とコンマ、ドット、英字)の排他的論理和を計算して、16進の2桁で表示したいのですが、printf("%x",moji[0]^moji[1]^moji[2]);などとやっていては非効率的すぎなので、for文などでループさせるのがいいのかなと思いましたが、
char a = 0x00;
for(int x = 0; x <= (sizeof moji/sizeof(char))-1 ){
a =moji[x]^moji[x+1];
}
とした場合、計算させたい配列が来た場合にエラーになってしまいます。(趣味程度の知識ので)
簡単な解決策をアドバイスいただけますでしょうか。
よろしくお願いします。

下記、char moji[]={""};に入っている文字;。*の次の2文字が送られてくるチェックサムです。
文字数は変化します。
$GNRMC,235037.000,A,1233.1234,N,12345.6543,E,101.110,858.31,300419,,,D*4F

質問者からの補足コメント

  • すいません自己解決しました。
    ありがとうございます。
    忘備録としてソースを載せます。
    int main(){


    char a[] = { "$GNRMC,235037.000,A,1233.1234,N,12345.6543,E,101.110,858.31,300419,,,D*4F"};

    char b = 0x00;
    char len = 0;

    len = strlen(a)-4;
    for (int x = 1; x <= len; x++) {
    b = b ^ a[x];
    }
    printf("0x%x\n", b);

    No.2の回答に寄せられた補足コメントです。 補足日時:2019/05/01 13:30

A 回答 (2件)

いろいろと突っ込み所があります。




> 計算させたい配列が来た場合にエラーになってしまいます

具体的に、どんなタイミングで、どんなエラーになるのですか?

例えば
for(int x = 0; x <= (sizeof moji/sizeof(char))-1 ){
は文法的に間違っているので、コンパイル時にエラーになります。
もし、書き写したときに間違えた、ということなら、「書き写す」のではなく「コピーして貼り付け」てください。


○ char moji[]={""};

char moji[1]={'\0'};
の省略形と解釈されます。
これだと、配列mojiは1要素しか確保されていません。
「文字列」として扱う場合には 「0文字の文字列」 しか格納できません。

正確に言うと、C言語の場合、確保した配列の範囲を越えて格納(代入)させようとすることはできます。
ただし、そのときに正しく格納できる保証はありません。

この moji に $GNR〜 を格納しようとすれば、確実に配列mojiの範囲を越えるので、当然、正しく格納できる保証はありません。
場合によっては、動作時にエラーになります。
/* 何食わぬ顔でそのまま実行が続くこともあります */

○ a =moji[x]^moji[x+1];
xはforループで、 0から配列mojiの要素数-1,つまり、 mojiの最初の添字から最後の添字までをループします(おそらく)
x=最後の添字
のときに
x+1 = 最後の添字の「次」
になります。
ここでも、配列範囲外のアクセスが発生しています。

○ a =moji[x]^moji[x+1];
この記述だと

前回までの計算結果を破棄して、新しくmoji[x]^moji[x+1]の結果をa に代入する

という意味になります。
学習時に「配列内の数値の合計を求める」というようなプログラムをやったはずです。
それの応用になります。

○ sizeof moji/sizeof(char)
sizeof moji は moji の大きさを求めます。
これは 「mojiが示している文字列の大きさ」では **ありません**
char txt[512] = "text" ;
なら、
sizeof txt = 512
txtの文字列長 = 4
です。

/*
また、sizeof moji が配列の大きさを表わしているとは限りません。
void checksum(char moji[] ) {
〜 sizeof moji 〜
}
とした場合等、範列ではなくポインタになっていることがあります。
*/

学習時に「strlen関数を自作する」というような問題なかったですか?
それの応用になります。


○「$から*の文字間」とありますが、提示された中にそのような判定を行っている様子がありません。
mojiに格納されているのが1行全てなら、このforの中でxorするかどうかを判定する必要があります。
mojiに格納されているのが「$から*の文字間」なら判定は不要です。
/* 「$から*」を格納する方法が間違っている可能性もありますが */
この回答への補足あり
    • good
    • 0
この回答へのお礼

ご回答有り難うございます。
補足させていただきます。
C言語は全くの独学ですので学校では一切習っておりませんVB程度でです。
エラーは、アクセス違反です。
本来の機器はPICマイコンですので、焼く前のテストとしてVC++ 2017にてテストしています。
GPSデータの受信はRS-232Cで受信しPIC依存の読み込み処理RCREGで読み込みます。
バッファを128バイト用意しましたので、全文字バッファに読み込みます。
よろしくお願いします。
-----下記、ソースコピーペ-----
char a[] = { "$GNRMC,235037.000,A,1233.1234,N,12345.6543,E,101.110,858.31,300419,,,D*7B" };
char hairtu_count = 0;
char b = 0x00;
char c = 0x00;
char len = 0;
len = strlen(a);
hairtu_count = sizeof(a) / sizeof(char);
printf("%lu\n\n", hairtu_count); // 配列の要素数
for (int x = 0; x <= hairtu_count - 1; x++) {
b = a[x] ^ a[x+1];
c = 1 ^ 0 ^ 1 ^ 0 ^ 1;
}
printf("0x%x\n", b); // 0x00と出力
printf("0x%x\n", c); // 0x01と出力
}

お礼日時:2019/05/01 13:01

まず


a =moji[x]^moji[x+1];
では計算できません。
a =a^moji[x];
ですね。

moji[x+1] では配列の範囲を超えてしまいますね。

for分に増分がありませんから永久ループになるのでは。

sizeof moji/sizeof(char)意味があるのか無いのか

mojiの定義がありません。
ポインタで定義されていればサイズは不明ですね。
sizeof(char)が1以外であれば結果が16進2桁にはなりませんね。
この場合上位を捨てるのか、下位を捨てるのか、上位^下位にするのかなど定義やコンパイラ、計算系で違ってくるでしょう。
    • good
    • 0
この回答へのお礼

ご返信有難うございます。
不要なコードだらけでしたので、コピペでなく手打ちをしていたらいろいろ抜けてしまいました。

お礼日時:2019/05/01 13:03

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!