• ベストアンサー

オーバーフローについて。

/* 符号無しの算術演算がオーバーフローを起こさないことを確認 */ という、ソースについて教えてください。 #include <stdio.h> #include <limits.h> int mani(void) { unsigned x = UINT_MAX - 1; printf("unsigned型の最大値:%u\n", UINT_MAX); printf("x = %n\n", x); printf("x + 3 = %u\n", x + 3); printf("x * 2 = %u\n", x * 2); return(0); } まず、 (1)unsigned x = UINT_MAX - 1; についてですが、何故1を引く必要があるのでしょうか? 別に1を引かなくてもいい気がするのですが・・・ (2)printf("x + 3 = %u\n", x + 3);  printf("x * 2 = %u\n", x * 2); についてですが、x = 65534 に + 3 にしたり、* 2 にすることで、何が言いたいのかがわからないので、教えてください。

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

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

★回答ではないが1つ。 >%nだとコンパイル時か実行時にエラーになるはずです。  ↑  『%n』という書式制御文字があります。  『%n』が処理系依存か知らないけど昔 sprintf() 関数を忠実に実装した経験があるので  覚えていました。そこでマニュアルを再度調べたら >整数へのポインタ  を引数に与え(scanfみたいにポインタを引数にする) >ストリームまたはバッファにこれまでに書き込まれた文字数。 >この値は、アドレスが引数として与えられた整数に格納されます。  となっています。 ・なのでもし『%u』ではなく『%n』が正しいとすると  『printf( "x = %n\n", &x );』として『x』には『4』がセットされることになる。  でも今回の場合はやっぱ『%u』だろうね。  main() 関数を『mani(void)』って記述ミスしていますしね。 本題: ・(1)について多分は UINT_MAX が 65536 だと思い違いをしてプログラミングを行い  1 を引いているのでは?と思う。  あるいは 1 引くことで +3 すればオーバーフローとしてちゃんと処理されることを  期待しているのかも。つまり x が UINT_MAX だと既に最大値なので加算の処理を  内部で行わない場合も考慮して 1 を引いておき UINT_MAX ではない値にしているかも。 ・(2)については float、double、long double などの浮動小数点と符号なし整数との  オーバーフローを起こさないか、起こすかの確認だと思います。  つまり、浮動小数点(double)の場合は <float.h> ヘッダにある DBL_MAX よりも  大きい数になるとオーバーフローとして『1.#INF00000000000e+000』という表示に  なります。決して最大値の『1.7976931348623158e+308』とか表示されるわけではない。  このことを確認するプログラムではないでしょうか?  下にサンプルを載せます。 サンプル: #include <stdio.h> #include <float.h> #include <limits.h> // メイン関数 int main( void ) {  unsigned x = UINT_MAX - 1;  double a = DBL_MAX;    // unsigned型  printf( "unsigned型の最大値:%u\n", UINT_MAX );  printf( "x = %u\n", x );  printf( "x + 3 = %u\n", (x + 3) );  printf( "x * 2 = %u\n", (x * 2) );  printf( "\n" );    // double型  printf( "double型の最大値:%.20e\n", DBL_MAX );  printf( "a = %.20e\n", a );  printf( "x + 3 = %.20e\n", (a + 3) );  printf( "x * 2 = %.20e\n", (a * 2) );  printf( "\n" );    return 0; } 実行結果: unsigned型の最大値:4294967295 x = 4294967294 x + 3 = 1 x * 2 = 4294967292 double型の最大値:1.79769313486231570000e+308 a = 1.79769313486231570000e+308 x + 3 = 1.79769313486231570000e+308 x * 2 = 1.#INF0000000000000000e+000 となりました。 私の環境は Windows XP Home SP2 です。 unsigned型が 32 ビットなので最大値は 65535 ではなく 4294967295 となっています。 最後に: ・この質問のプログラムは、浮動小数点と符号なし整数型のオーバーフローの確認と思われます。  多分、ソースを書いている人は符号なし整数型なら『1.#INF0000000000000000e+000』表示と  言う意味合いのオーバーフローは起こらないと言いたいのかもしれない。  本当はオーバーフローは起こしていて、単にその部分を捨てた情報を処理するだけだけど  ソースの書いている人は『1.#INF0000000000000000e+000』表示をオーバーフローと表現して  いるのかもしれない。と推測します。 ・そう考えると『x + 3』や『x * 2』の場合は小さい数の +3 ではオーバーフローとして  『1.#INF0000000000000000e+000』表示されず、2倍の時にオーバーフローとして  『1.#INF0000000000000000e+000』表示される。を符号なし整数unsigned型で確認した。  という事でしょう。と私は推測します。 ・以上。参考に。→最終的にはソース書いた本人に聞くのが一番だ。

hatenan114
質問者

お礼

回答ありがとうございます。 凄く理解しました。 また宜しくお願いします。

すると、全ての回答が全文表示されます。

その他の回答 (3)

回答No.3

まず、コードの内容について、確認してください。 3行目 int mani→int main 7行目 %n → %u 質問者さまのC環境では、unsignedは16ビット符号なし整数のようですね。2の16乗で65536です。(私の使用環境では、32bitです) (1)については、このコードの目的から見ると、1を引く必要性はないようですね。理由は良く分かりません。 (2)については、 普通に計算すれば、X=65536-1=65535として X+3で、65538(1 0000 0000 0000 0010) X*2で、131070(1 1111 1111 1111 1110) となります。でも、ここのunsignedは16ビットですから、上に書いた二進数表現を見ていただくと、1桁桁あふれしています。 この2つの2進数の頭の1が、オーバーフローして扱えなくなるので、出てくる答えが違ってきます。 以下のようになるはずです。 X+3→2(0000 0000 0000 0010) X*2→65534(1111 1111 1111 1110) というようなことが言いたいのではないでしょうか?? コードを書いた人に尋ねるのが一番かと思います。 上記コメントは、環境の違いなどもあるようですので、あくまで参考ということでよろしくお願いします。

hatenan114
質問者

お礼

すみません。 私の入力ミスでした。 回答内容もわかりやすくて、理解できました。 参考にいたします。

すると、全ての回答が全文表示されます。
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.2

環境はVisualStudioでしょうか? とりあえず環境不明ということで答えを書きます。 >(1)unsigned x = UINT_MAX - 1; >についてですが、何故1を引く必要があるのでしょうか? >別に1を引かなくてもいい気がするのですが・・・ 私もそう思います。 書いた人の趣味としか言いようがありません。 >(2)printf("x + 3 = %u\n", x + 3); > printf("x * 2 = %u\n", x * 2); >についてですが、x = 65534 に + 3 にしたり、* 2 にすることで、何が言いたいのかがわからないので、教えてください。 まず間違いなく両方とも整数演算でオーバーフローします。でも、「符号無しの算術演算がオーバーフローを起こさないことを確認」というコメント矛盾しますね。正確にはオーバーフローは発生するが、オーバーフロー例外が発生して停止しない事の確認だと思います。言語やコンパイラにより動作が違うので絶対オーバーフロー例外が発生しないわけではありません。 それとVisualStudioやcygwinなどの環境ならUINT_MAXは65535では無いと思います。unsigned x;は省略されていますが、unsigned int x;だと思いますので、unsigned intの最大値は(2の32乗-1)です。 >printf("x = %n\n", x); ここは%nじゃなくて%uだと思いますが違いますか? %nだとコンパイル時か実行時にエラーになるはずです。

hatenan114
質問者

お礼

回答ありがとうございます。 実行エラーになりました。 私の入力ミスでした。

すると、全ての回答が全文表示されます。
回答No.1

オーバーフローの意味は分かりますか?

すると、全ての回答が全文表示されます。

関連するQ&A