- ベストアンサー
16進数の計算の仕方を教えて下さい
C言語始めたばかりのレベルです。 C言語(MicrosofrC Ver6.0)で16進数の計算をしています。 配列に書かれている16進数を計算させようとしたのですが、計算結果が正しく出ません。 計算が正しく無いのか、表示のさせ方が正しく無いのかも分からない状態です。助けて下さい。 下記の書き方をすると warning C4056: overflow in constant arithmeticのエラーが、 x= の所の (b_header[6] * 100));と data = の所の(b_header[3] * 1000000));の行に出ます。 プログラムは以下の通りです。 char b_header[32] = {0}; /* size */ int x_size; int y_size; long data_size; long x; void main() { b_header[0] = 0x30; b_header[1] = 0x80; b_header[2] = 0x73; b_header[3] = 0x02; b_header[4] = 0; b_header[5] = 0xaf; /* Y */ b_header[6] = 0x27; b_header[7] = 0; b_header[8] = 0xcf; /* X */ b_header[9] = 0x0f; x_size = (int) (b_header[8]+(b_header[9]*100)); y_size = (int) (b_header[5]+(b_header[6]*100)); x = (long)(b_header[0]+(b_header[1] * 100)+(b_header[2] * 10000)+(b_header[3] * 1000000)) / (long)(b_header[5]+(b_header[6] * 100)); data_size =(long) (b_header[0]+(b_header[1] * 100)+(b_header[2] * 10000)+(b_header[3] * 1000000)); printf("\n data_size = %d",data_size); printf("\n y_size = %d",y_size); printf("\n X = %d",x); printf("\n X_size = %d",x_size); }
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
>b_header[5] = 0xaf; /* Y */ >b_header[6] = 0x27; や >b_header[8] = 0xcf; /* X */ >b_header[9] = 0x0f; と入ってるなら、Xは4047、Yは10259の筈。 でも、 >x_size = (int) (b_header[8]+(b_header[9]*100)); >y_size = (int) (b_header[5]+(b_header[6]*100)); を実行すると、x_sizeは1707、y_sizeは4075になる。 これは合ってるだろうか? b_header[8] = 0x00; /* X */ b_header[9] = 0x01; の時と b_header[8] = 0x64; /* X */ b_header[9] = 0x00; の時 x_size = (int) (b_header[8]+(b_header[9]*100)); を実行すると、どちらも、x_sizeは100になる。 b_header[8]、b_header[9]の中身が違うのに、どうしてx_sizeが同じ値の100になってしまうのだろう? 理由は「計算式が間違ってるから」だ。 あと、 >x_size = (int) (b_header[8]+(b_header[9]*100)); >y_size = (int) (b_header[5]+(b_header[6]*100)); >x = (long)(b_header[0]+(b_header[1] * 100)+(b_header[2] * 10000)+(b_header[3] * 1000000)) / (long)(b_header[5]+(b_header[6] * 100)); >data_size =(long) (b_header[0]+(b_header[1] * 100)+(b_header[2] * 10000)+(b_header[3] * 1000000)); は、キャストするタイミングが悪い。 オーバーフローが起こった後の結果を、一生懸命intやlongにキャストしたって手遅れ。 x_size = (int)b_header[8]+(int)b_header[9]*256; y_size = (int)b_header[5]+(int)b_header[6]*256; x = ((long)b_header[0]+(long)b_header[1]*256L+(long)b_header[2]*65536L+(long)b_header[3]*16777216L) / ((long)b_header[5]+(long)b_header[6]*256L); data_size =(long)b_header[0]+(long)b_header[1]*256L+(long)b_header[2]*65536L+(long)b_header[3]*16777216L; にしないと駄目。 それより x_size = (int)b_header[8]+(int)b_header[9]<<8; y_size = (int)b_header[5]+(int)b_header[6]<<8; x = ((long)b_header[0]+(long)b_header[1]<<8+(long)b_header[2]<<16+(long)b_header[3]<<24) / ((long)b_header[5]+(long)b_header[6]<<8); data_size =(long)b_header[0]+(long)b_header[1]<<8+(long)b_header[2]<<16+(long)b_header[3]<<24; の方が良いでしょう。掛け算よりビットシフトの方が早い。
その他の回答 (5)
- Tacosan
- ベストアンサー率23% (3656/15482)
もうほとんど他の人が述べているので指摘だけ: integer promotion で勝手に int になっているはずなので, *その点だけなら*キャストは不要なはずです>#5. char を使ってる時点で危険なんだけど. あと, シフトより加減算が優先されるのも注意ですね>#4.
お礼
ご回答ありがとうございます。 補足説明をして頂いたので、()でくくってみました。 皆さんのご回答を元に、 char b_header[32] = {0}; --> unsigned char b_header[32] = {0};に 16進数計算の所は x_size = (int) (b_header[8]+(b_header[9]*100)); -->x_size = ((unsigned int)b_header[8])+((unsigned int)b_header[9]<<8); ※ご指摘を頂いた優先順位は修正ミスで()をつけ忘れた部分があった時、+が先に計算されてしまいました。 データの表示がちゃんと出なかった所も、修正しました。 printf("\n data_size = %ld",data_size); 皆様のお陰で思った通りの計算が出来ただけでなく、シフト演算が理解出来てとても嬉しかったです。 本当にありがとうございました
- arain
- ベストアンサー率27% (292/1049)
No.2です。 誤記訂正 >ans = (n[2] << 8) | (n[1] << 8) | n[0] ans = (n[2] << 16) | (n[1] << 8) | n[0] が正しい。 それでで、シフトするとchar型を超えるので、それぞれにキャストが必要。
- equinox2
- ベストアンサー率48% (321/660)
watcomのCでコンパイルしたら同じエラーにはなりませんでした。 以下は(1)のみ直した結果です data_size = 3162848 y_size = 4075 X = 776 X_size = 1707 (1)まず、 char b_header[32] = {0}; は unsigned char b_header[32] = {0}; にしましょう。 (2)16進数で2738030/27AF・・・ ソースでは、27AFで割るようになっていません。 (b_header[6] * 100 の部分は (b_header[6] * 256 でしょう。 もしくは 0x0100 vc6のintは32bitだと思ったのですが、どんなコンパイルオプションでしょうか?
お礼
ご回答ありがとうございます。 >vc6のintは32bitだと思ったのですが、どんなコンパイルオプションでしょうか? /W3 /AH /F 8000 でコンパイルしました。 コンパイルオプションも実の所あまり詳しくないので、こう書いてコンパイルして下さいと言われてそのまましております。 ワーニングレベルを高く設定していると言う事だけは分かるのですが・・・。
- arain
- ベストアンサー率27% (292/1049)
No.1の返答より ・キャスト不足 ・n倍の間違い はわかる。16進数だから、「n * 100」じゃなく「n * 0x100」にしないといけない。他も同様。 というよりも、なぜシフト演算と論理和使わないの? 3Byteなら、 ans = (n[2] << 8) | (n[1] << 8) | n[0] で同じなのに(見やすいようにキャストは省いている)。
お礼
お返事ありがとうございます >16進数だから、「n * 100」じゃなく「n * 0x100」にしないといけない。 仰る通りでした。16進数なのに0xにしなければ当然計算は正しくされませんよね。 情けない事に、ご指摘されるまで全く気づきませんでした。 何故と言われても、シフト演算を使った事が無かったので。 シフト演算を調べてみます。
- Tacosan
- ベストアンサー率23% (3656/15482)
「計算結果が正しく出ません」と言われてもねぇ.... ・あなたはどのような出力を期待したのですか? ・実際の出力がどうなっているのですか?
補足
ご返答ありがとうございます xの計算結果についてですが、16進数で2738030/27AFの計算結果をFD0(4048)となるようにしたいのですが、計算結果はエラーの出る前には4048にならなかったので、その後いろいろいじっているうちに、コンパイルエラーでexeが作成されなくなりました(以前のものは削除してしまい、実行結果を確認出来ません) 今は配列の中身を固定していますが、毎回同じ部分を読んで計算させたいのです。
お礼
ご丁寧な解説ありがとうございます。 全てにキャストを書かなければならなかったのですね。 何度かやっているうちに、桁の大きいものの前にだけキャストをつけてみたりしたのですが・・・。(多分その時exeが出来たと思われます) 根本的に計算のさせ方が間違っていたので、結局キャストをもう一度取ってしまい、結果コンパイルエラーになったようです。 キャストのタイミングまで考慮出来ていなかった事を教えて頂きありがとうございます(本人としては情けない限りですが)これからはタイミングを十分考慮してキャストしたり、キャストしなくてすむ方法を考えて見ます。 他の回答者様もお書きになられていたのですが、シフト演算というものをもっと勉強すると見た目もスッキリして簡単になる事を学びました。 chie65536様のように書いて頂けてさらに分かりやすかったです。 ありがとうございました。