重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

【GOLF me!】初月無料お試し

/*
符号無しの算術演算がオーバーフローを起こさないことを確認
*/
という、ソースについて教えてください。

#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 にすることで、何が言いたいのかがわからないので、教えてください。

A 回答 (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型で確認した。
 という事でしょう。と私は推測します。
・以上。参考に。→最終的にはソース書いた本人に聞くのが一番だ。
    • good
    • 0
この回答へのお礼

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

お礼日時:2007/08/12 16:38

まず、コードの内容について、確認してください。


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)

というようなことが言いたいのではないでしょうか??

コードを書いた人に尋ねるのが一番かと思います。

上記コメントは、環境の違いなどもあるようですので、あくまで参考ということでよろしくお願いします。
    • good
    • 0
この回答へのお礼

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

お礼日時:2007/08/12 16:41

環境は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だとコンパイル時か実行時にエラーになるはずです。
    • good
    • 0
この回答へのお礼

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

お礼日時:2007/08/12 16:42

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

    • good
    • 0

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