
/*
符号無しの算術演算がオーバーフローを起こさないことを確認
*/
という、ソースについて教えてください。
#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 にすることで、何が言いたいのかがわからないので、教えてください。
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型で確認した。
という事でしょう。と私は推測します。
・以上。参考に。→最終的にはソース書いた本人に聞くのが一番だ。
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)
というようなことが言いたいのではないでしょうか??
コードを書いた人に尋ねるのが一番かと思います。
上記コメントは、環境の違いなどもあるようですので、あくまで参考ということでよろしくお願いします。
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だとコンパイル時か実行時にエラーになるはずです。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
コンパイルエラーについて
-
H8マイコンCでprintf/scanfが使...
-
「%n」や「%S」は何故恥ずかし...
-
C言語プログラミング
-
C言語の勉強しています。すみま...
-
C言語で四則演算を使って10を作...
-
ピラミッド表示プログラム。
-
ホームページをC言語で作りたい...
-
最早開始時間と最遅完了時刻を...
-
Aの値からBの値を除するとは??
-
信頼区間の1.96や1.65ってどこ...
-
#define _CRT_SECURE_NO_WARNIN...
-
C言語 エラーの原因がわからな...
-
値差の%計算方法について
-
数字以外が入力されたらエラー...
-
「Aに対するBの割合」と「Aに対...
-
VB6.0での小数点の扱いについて
-
【C++】関数ポインタの使い方
-
c languageで 簡単な質問があ...
-
ある商品のロス率を5%見込み、...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
10個出力で改行したいのですが...
-
コンパイルエラーについて
-
CTRL+Dでループを抜けるには
-
Cプログラムについて
-
コマンドラインに出力した文字...
-
WM_CLOSEで閉じれないウィンド...
-
C言語の&に関する質問
-
すごろくに使用するサイコロ
-
文字と数字の判定について
-
printf( " %2d", p * q );
-
【C言語教えてください】sin波...
-
%P と %X の違い
-
C言語の勉強しています。すみま...
-
strcmp
-
c言語でAからZまでを表示する...
-
unsigned int型について
-
(C言語)めちゃくちゃな値にな...
-
printf で二進表示を行いたい。
-
プログラミング C言語 課題でプ...
-
c言語で2000年以降カレンダーを...
おすすめ情報