• ベストアンサー

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); }

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

  • ベストアンサー
  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.4

>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; の方が良いでしょう。掛け算よりビットシフトの方が早い。

siriusu-1
質問者

お礼

ご丁寧な解説ありがとうございます。 全てにキャストを書かなければならなかったのですね。 何度かやっているうちに、桁の大きいものの前にだけキャストをつけてみたりしたのですが・・・。(多分その時exeが出来たと思われます) 根本的に計算のさせ方が間違っていたので、結局キャストをもう一度取ってしまい、結果コンパイルエラーになったようです。 キャストのタイミングまで考慮出来ていなかった事を教えて頂きありがとうございます(本人としては情けない限りですが)これからはタイミングを十分考慮してキャストしたり、キャストしなくてすむ方法を考えて見ます。 他の回答者様もお書きになられていたのですが、シフト演算というものをもっと勉強すると見た目もスッキリして簡単になる事を学びました。 chie65536様のように書いて頂けてさらに分かりやすかったです。 ありがとうございました。

その他の回答 (5)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.6

もうほとんど他の人が述べているので指摘だけ: integer promotion で勝手に int になっているはずなので, *その点だけなら*キャストは不要なはずです>#5. char を使ってる時点で危険なんだけど. あと, シフトより加減算が優先されるのも注意ですね>#4.

siriusu-1
質問者

お礼

ご回答ありがとうございます。 補足説明をして頂いたので、()でくくってみました。 皆さんのご回答を元に、 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.5

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)
回答No.3

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だと思ったのですが、どんなコンパイルオプションでしょうか?

siriusu-1
質問者

お礼

ご回答ありがとうございます。 >vc6のintは32bitだと思ったのですが、どんなコンパイルオプションでしょうか? /W3 /AH /F 8000 でコンパイルしました。 コンパイルオプションも実の所あまり詳しくないので、こう書いてコンパイルして下さいと言われてそのまましております。 ワーニングレベルを高く設定していると言う事だけは分かるのですが・・・。

  • arain
  • ベストアンサー率27% (292/1049)
回答No.2

No.1の返答より ・キャスト不足 ・n倍の間違い はわかる。16進数だから、「n * 100」じゃなく「n * 0x100」にしないといけない。他も同様。 というよりも、なぜシフト演算と論理和使わないの? 3Byteなら、 ans = (n[2] << 8) | (n[1] << 8) | n[0] で同じなのに(見やすいようにキャストは省いている)。

siriusu-1
質問者

お礼

お返事ありがとうございます >16進数だから、「n * 100」じゃなく「n * 0x100」にしないといけない。 仰る通りでした。16進数なのに0xにしなければ当然計算は正しくされませんよね。 情けない事に、ご指摘されるまで全く気づきませんでした。 何故と言われても、シフト演算を使った事が無かったので。 シフト演算を調べてみます。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

「計算結果が正しく出ません」と言われてもねぇ.... ・あなたはどのような出力を期待したのですか? ・実際の出力がどうなっているのですか?

siriusu-1
質問者

補足

ご返答ありがとうございます xの計算結果についてですが、16進数で2738030/27AFの計算結果をFD0(4048)となるようにしたいのですが、計算結果はエラーの出る前には4048にならなかったので、その後いろいろいじっているうちに、コンパイルエラーでexeが作成されなくなりました(以前のものは削除してしまい、実行結果を確認出来ません) 今は配列の中身を固定していますが、毎回同じ部分を読んで計算させたいのです。

関連するQ&A

  • 画素数の計算について

    現在BMPで640×480の画像の左右両端の80画素ずつ切り取り480×480の画像を作って さらに、8×8のブロックに分けて各ブロックごとの光の強度をだすプログラミングをつくっているのですが、 (各ブロックはそれぞれ[1][1]~[8][8]となづけています) [1][8]、[2][8]、[3][8]…と8がつくブロックの強度がすべて0になってしまいます。 いろいろと考えてみたのですが、どうにもうまくいかずに悩んでおります。 助けていただけませんでしょうか? よろしくおねがいします。 おそらく、ここらへんがおかしいと思う部分をのせておきます。 /* 640側の左右80ずつ切り取り、480×480の正方形の画像にする */ int bunkatsu(BMP *rp,RESULT *res){ int x,y; int a=0; for(y = 0;y < rp->Bmpi.biHeight; y++){ for(x = 80;x < rp->Bmpi.biWidth - 80; x++){ res->data[a] = rp->blue[y * rp->Bmpi.biWidth + x] + rp->green[y * rp->Bmpi.biWidth + x] + rp->red[y * rp->Bmpi.biWidth + x]; a++; } } return 0; } /* 480×480を8×8のブロックに分け(60×60が64ブロック) 、各ブロックの明るさを計算する */ int keisan(BMP *rp,RESULT *res){ int b,c; int i=0,j=0; int x,y; for(y = 0;(y+60) < rp->Bmpi.biHeight;y+=60){ for(x = 0;(x + 60) < (rp->Bmpi.biWidth - 160);x+=60){ for(b = 0;b < 60;b++){ for(c = 0; c < 60;c++){ res->akarusa[i][j]+=res->data[(y + b) * rp->Bmpi.biWidth +(x + c)]; } } j++; } j=0; i++; } max(res); return 0; } /* 一番明るいブロックの特定 */ RESULT *max(RESULT *res){ int MAX1=0; int MAX2=0; int i=0; int j=0; for(i = 0;i < 8;i++){ for(j = 0;j < 8;j++){ printf("[%d][%d]=%d ",i+1,j+1,res->akarusa[i][j]); if(MAX1 < res->akarusa[i][j]){ MAX1 = res->akarusa[i][j]; res->maxi=i; res->maxj=j; } } printf("\n"); } printf("一番明るいブロックは[%d][%d]です\n",res->maxi + 1,res->maxj + 1); return 0; } です。よろしくおねがいします。

  • C90とC99の計算結果の違い?

    C言語の質問です。 gcc version 4.3.2 (Ubuntu 4.3.2-1ubuntu12) 以下のプログラムをgccでコンパイル・実行すると(1)に入り,"a"が出力されます。unsigned intの計算なのでラップアラウンドが生じtest=4294716272となるのは私の期待どおりです。 ただ、gcc -std=c99でコンパイル・実行すると(2)に入り,"b"が出力されました。c99でコンパイル・実行すると計算結果がなぜ異なっているのかが分かりません。 long test = 0; unsigned int x = 184; unsigned int y = 251208; test = (x-y); if(test == 4294716272){ printf("a");// (1) }else if(test == -251024){ printf("b"); // (2) }

  • プログラミングCの四則計算について質問です

    どうしてもわからなかったのでご指摘お願いします。 以下のプログラムを四則計算ができるプログラムに変更したいのですがどこを直せばいいのでしょうか? /* ansp5_7 */ #include <stdio.h> void wasa(int a,int b,int *w,int *x,int *y,float *z); main() { int d1,d2,wa,sa,seki; float syou; printf("data1,data2="); scanf("%d,%d",&d1,&d2); wasa(d1,d2,&wa,&sa,&seki,&syou); printf("wa=%d,sa=%d,seki=%d,syou=%5.2f\n",wa,sa,seki,syou); } void wasa(int a,int b,int *w,int *x,int *y,float *z) { *w=a+b; *x=a-b; *y=a*b; *z=(float)a/b; }

  • 配列

    このプログラムを #include<stdio.h> int x,y; int n; void RUL(int n),DLU(int n),LDR(int n),URD(int n); main() { scanf("%d",&n); printf("#位相%dのヒルベルト曲線\n",n); x=0; y=0;printf("(%d %d) \n)",x,y); RUL(n); } void RUL(int n) { if(n<=0) {return;} URD(n-1);x=x+1;printf("(%d %d)\n",x,y); RUL(n-1);y=y+1;printf("(%d %d)\n",x,y); RUL(n-1);x=x-1;printf("(%d %d)\n",x,y); DLU(n-1); } void DLU(int n) { if(n<=0) {return;} LDR(n-1);y=y-1;printf("(%d %d)\n",x,y); DLU(n-1);x=x-1;printf("(%d %d)\n",x,y); DLU(n-1);y=y+1;printf("(%d %d)\n",x,y); RUL(n-1); } void LDR(int n) { if(n<=0) {return;} DLU(n-1);x=x-1;printf("(%d %d)\n",x,y); LDR(n-1);y=y-1;printf("(%d %d)\n",x,y); LDR(n-1);x=x+1;printf("(%d %d)\n",x,y); URD(n-1); } void URD(int n) { if(n<=0) {return;} RUL(n-1);y=y+1;printf("(%d %d)\n",x,y); URD(n-1);x=x+1;printf("(%d %d)\n",x,y); URD(n-1);y=y-1;printf("(%d %d)\n",x,y); LDR(n-1); } 実行結果は (0 0) (0 1) ・ ・ ・ (0 254) (0 255) になります。これを2次元配列で表したのですがどのようにいじればいいでしょうか?おねがいします。

  • c言語 パスカルの三角形

    c言語でパスカルの三角形を出力するプログラムを作りたいのですが、上手くいきません。 何を直せばいいのか教えてください。 #include <stdio.h> #define N 10 int main(void){ int i, j = 1, x, y; int d[N][N]; /* 三角形を作成 */ for (i = 1 ; i < N ; i++){ d[i][0] = 1; while (j <= i - 1){ d[i][j] = d[i-1][j-1] + d[i-1][j]; j ++; } } /* 三角形の表示 */ for (y = 0; y < N; y++) { for (x = 0; x < N-y; x++) printf(" "); for (x = 0; x < y; x++) printf("%3d ", d[x][y]); printf("\n"); } return 0; } 実行結果 -2147417616 2665208 1629976532 1627572249 1629101723 1 1629982744 2665256 2665548 3407923 1629345053 1627571017 0 3538997 1629739051 10 1629345053 2665368 3670071 2665384 1629739040 1627927140 2665244 1628040295 57 1628810863 1629476960 1628602749 2665560 2665304 1629345053 0 1629739040 1629740576 1628992224 2 4411498 1628040588 -2147417600 0 1629476960 1629740664 1629739040 1 267574 0

  • プログラムC

    前にも質問したのですがヒルベルト曲線を用いて画像をスキャンするプログラムとビットマップの画像を読み込むプログラムを用いてお互いの座標を関連付けてヒルベルト曲線の座標にビットマップの1画素ずつの値を代入したいのですがどうしてもうまくいかなく質問しました。 前に質問した物はhttp://oshiete1.goo.ne.jp/kotaeru.php3?q=1106704 にあります。ヒルベルトは質問覧にビットマッピはNO2の補足にあります。プログラムを書くと800字を超えてしまうのでそのようにしました。 ヒルベルトは他に #include<stdio.h> int x,y; int n; void RUL(int n),DLU(int n),LDR(int n),URD(int n); main() { scanf("%d",&n); printf("#位相%dのヒルベルト曲線\n",n); x=0; y=0;printf("(%d %d) ",x,y); RUL(8); } void RUL(int n) { if(n<=0) {return;} URD(n-1);x=x+1;printf("(%d %d)",x,y); RUL(n-1);y=y+1;printf("(%d %d)",x,y); RUL(n-1);x=x-1;printf("(%d %d)",x,y); DLU(n-1); } void DLU(int n) { if(n<=0) {return;} LDR(n-1);y=y-1;printf("(%d %d)",x,y); DLU(n-1);x=x-1;printf("(%d %d)",x,y); DLU(n-1);y=y+1;printf("(%d %d)",x,y); RUL(n-1); } void LDR(int n) { if(n<=0) {return;} DLU(n-1);x=x-1;printf("(%d %d)",x,y); LDR(n-1);y=y-1;printf("(%d %d)",x,y); LDR(n-1);x=x+1;printf("(%d %d)",x,y); URD(n-1); } void URD(int n) { if(n<=0) {return;} RUL(n-1);y=y+1;printf("(%d %d)",x,y); URD(n-1);x=x+1;printf("(%d %d)",x,y); URD(n-1);y=y-1;printf("(%d %d)",x,y); LDR(n-1); } があります。

  • ヒルベルト曲線のプログラム(C言語)

    私は画像の勉強をしています。それで従来の水平スキャンではなく2次元相関をたもったまま1次元配列に変換できるヒルベルトスキャンとBWT変換とエントロピー符号化を用いて圧縮する方法を勉強しています。しかしヒルベルトのほうができなくて困っています。 プログラムの実行結果でヒルベルト曲線通る座標を示すプログラムを教えてください。だいたいは書けましたがうまくいきません。プログラムは #include<stdio.h> int x,y; main() { int n; void RUL(int n),DLU(int n),LDR(int n),URD(int,n); scanf("%d",&n); printf("#位相%dのヒルベルト曲線\n",n); x=0; y=0;printf("%d\n",x,y); RUL(n);printf("\n"); } void RUL(int n) { if(n<=0) {return;} URD(n-1);x=x+1;printf("%d %d\n",x,y); RUL(n-1);y=y+1;printf("%d %d\n",x,y); RUL(n-1);x=x-1;printf("%d %d\n",x,y); DLU(n-1); } void DLU(int n) { if(n<=0) {return;} LDR(n-1);y=y-1;printf("%d %d\n",x,y); DLU(n-1);x=x-1;printf("%d %d\n",x,y); DLU(n-1);y=y+1;printf("%d %d\n",x,y); RUL(n-1); } void LDR(int n) { if(n<=0) {return;} DLU(n-1);x=x-1;printf("%d %d\n",x,y); LDR(n-1);y=y-1;printf("%d %d\n",x,y); LDR(n-1);x=x+1;printf("%d %d\n",x,y); URD(n-1); } void URD(int n) { if(n<=0) {return;} RUL(n-1);y=y+1;printf("%d %d\n",x,y); URD(n-1);x=x+1;printf("%d %d\n",x,y); URD(n-1);y=y-1;printf("%d %d\n",x,y); LDR(n-1); } です。それをBWT変換とエントロピー符号にかけ圧縮させその圧縮率を求めその後画像はちゃんと戻るかを調べるために復元のプログラムを書かないいけませんがそのプログラムがわかりません。教えてください。

  • 桁数が増えると正しく計算されません。

    今、Perlで作成したモジュールをCに移しています。 Perlではうまく動いているのですが、Cで作った以下のプログラムでは、 nを13以上にすると、値が正しく計算されなくなります。 ユーザ関数をdoubleにしたりすると、全て0になったりコンパイルできません。 せめてdouble型の最大値くらいまでは計算したいと考えています。 また、下のプログラムでC言語ならではの修正すべき点があれば教えてください。 よろしくお願いします。 #-----------------------------------------------------------# #include <stdio.h> int factorial(int j); int main(void) { /* 試行回数n回 */ int i, j, n, r, x; int combination; //printf("試行回数は?"); //scanf("%d", &n); n=13; for (i=1; i<=n; i++){ for (r=0; r<=i; r++){ combination = factorial(i) / (factorial(r) * factorial(i - r)); printf("%5d",combination); } printf("\n"); } } int factorial(int j){ int i; int x; x = 1; for (i = 1; i <= j; i++){ x *= i; } return x; } #-----------------------------------------------------------#

  • 配列の要素数に変数を入れたい

    配列に数の入力履歴を入れて最後にその数を出力したいのですが、変数を入れることはできないと勉強した記憶がありまさにその通りコンパイルエラーが出ました。 他に何か方法はありませんでしょうか。 /* 課題1-3 */ #include <time.h> #include <stdio.h> #include <stdlib.h> #include <math.h> int main(void) { int i; int no1; /* 範囲1 */ int no2; /* 範囲2 */ int max; /* 大きい乱数 */ int min; /* 小さい乱数 */ int y; /* 当てさせる数 */ int stage; /* 入力回数 */ int x; /* 読み込んだ値 */ int n; /* 入力制限 */ srand(time(NULL)); no1 = rand(); no2 = rand(); if(no1 > no2){ max = no1; min = no2; } else{ max = no2; min = no1; } y = min + rand() % (max-min); n = ceil(log(max-min)/log(2)); int a[n]; /*←配列の要素数をn個にしたい*/ printf("%d以上%d以下の整数を当ててください。\n", min, max); stage = 0; do{ printf("残り%d回。いくつでしょう:\n", n - stage); scanf("%d", &x); a[stage++] = x; if(y > x) printf("小さいです。\n"); else if(y < x) printf("大きいです。\n"); }while(y != x && stage < n); if(y != x) printf("残念でした。正解は%dです。", y); else printf("正解です。%d回目で正解しました。", stage); puts("\n---入力履歴---"); for(i=0; i<stage; i++) printf("%2d : %4d %+4d\n", i+1, a[i], a[i] - y); return (0); }

  • C言語での計算

    C言語初心者で、計算するプログラムを作ってみようと思い、少ない知識で十進数を二進数にするプログラムを作ってみましたが、うまくいきません。 #include <stdio.h> #include <math.h> main () { int s, t, r; double x=10,y,n; printf("十進数は"); scanf("%d",&s); n = s / 2; r = s % 2; y = pow(x, n); t = y + r; printf("二進数は%d",t); return 0; } コンパイルして実行してみると、3つ問題が見つかりました。 (1)十進数が0のとき、二進数が1と表示される。 (2)十進数が1のとき、二進数が2と表示される。 (3)十進数が20以上のとき、正しい値が表示されない。 問題箇所を指摘していただけると幸いです。 よろしくお願いします。