###前提・実現したいこと
c言語の初心者です。printf関数について質問です。
###発生している問題・エラーメッセージ
以下のコードを実行した際想像とは違った結果になったため質問させていただきます
###該当のソースコード
#include<stdio.h> main() { double pi = 3.14; int test = 10; printf("pi=3.14を整数型で出力\t%d\n", pi); printf("test=10を小数型で出力\t%f\n", test); return 0; }
###実行結果
pi=3.14を整数型で出力 1374389535
test=10を小数型で出力 0.000000
###想像していた実行結果
pi=3.14を整数型で出力 3
test=10を小数型で出力 10.000000
1行目:小数を整数で出力すると小数点以下が切り捨てられると考え3が出力されると予想しましたが実際は意味不明な数字が出力されました。
2行目:整数を小数で出力すると小数点以下に0が付け足されて出力されると予想しましたが実際は0になりました。
以上2点について解説をお願いします。
なお実行はVisual Studio 2017をを用いました。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答5件
0
ベストアンサー
コンピュータはどんなデータも2進数で扱います。まずは、int型、double型の数値が、どのような形式でメモリに格納されるか、その違いをご理解ください。
int型は32bit(と、後述のように、表示結果から推測可能)なので、10 = 0x0000000a です(2進数の値は16進数で扱うのが現実的)。
一方、double型、即ち倍精度浮動小数点数の数値は64ビットの2進数です。
倍精度浮動小数点数の形式
intとdoubleでは、ビット数の違い(32bitと64bit)もさることながら、その中の各ビットの意味がまるで違う。この事を覚えておくと良いです。
pi=3.14を整数型で出力 1374389535
調べれば、3.14 は 0x40091eb851eb851f であることがわかります。もうひとつ、表示された 1374389535 という10進数を16進数で表わせば 0x51eb851f です。Windowsの電卓ユーティリティで、貴方もすぐ確認可能です。
見比べてください。1374389535 は、3.14 を2進数で表した64ビットの下位32ビットを、int型のデータとみなし10進数で表示した結果だとわかります。
test=10を小数型で出力 0.000000
printf() に渡されたのは 0x0000000a という32bitです。printf()が、%fという変換指定に従い、メモリ上のデータを見たら、おそらく(たまたま?) 0x000000000000000a だったのではないでしょうか。その64bitの値を倍精度浮動小数点数とみなした結果が 0.000000 でしょう。
printf関数は指定された書式に従ってメモリの内容を出力する動作
と、hmmmさんがズバリおっしゃった通りです。
このように、一見不可解に見える挙動は、データがどのような形でメモリに格納されているか、メモリ上の2進数値を調べると解決することが多くあります。
明示的キャスト・暗黙的キャストについて。
型の異なるもの同士の代入など、例えば test = pi; のような場合は、コンパイラが気を効かせて(笑)、型変換の処理をしてから代入してくれます。明示的なキャストをすれば、勿論そこに必要な型変換処理をしてくれます。
しかし、「メモリの内容を出力する」printf() に渡される引数が、暗黙的にキャストされることはありません。 printf("pi=3.14を整数型で出力\t%d\n", (int)pi);
の場合は、浮動小数点数を整数に変換した結果(即ち 0x00000003)が printf() に渡り、3 と表示されます。
こうした事は、コンパイル結果をアセンブリコードで確認すると明確になります。
追記:浮動小数点数が、どのような2進数になるのか、unionな変数を使うと容易に確認できます。
C
1 union { 2 double dval; 3 int ival[2]; 4 } upi; 5 6 upi.dval = 3.14; 7 printf("dvalを16進数で表示\t%x %x\n", upi.ival[1], upi.ival[0]);
実行結果です。
dvalを16進数で表示 40091eb8 51eb851f
念の為:printf("%x %x\n", upi.ival[1], upi.ival[0]);
という順序で表示する理由は、私達が使うパソコンのCPUが、リトルエンディアンでメモリをアクセスするからです。
投稿2017/07/20 23:20
編集2017/07/21 02:07総合スコア1380
0
printf関数は指定された書式に従ってメモリの内容を出力する動作になります。
ですので、イメージとしては以下のようにdoubleのメモリ内容をそのままint型の変数にコピーしてprintfした結果と同じになります。
vinegar1217さんの期待する結果を得たい場合はキャストする必要があります。
c++
1#include<stdio.h> 2 3int main() 4{ 5 double pi = 3.14; 6 int test = 10; 7 int pi_as_int = 0; 8 float test_as_float = 0; 9 memcpy(&pi_as_int, &pi, sizeof(pi_as_int));//メモリの内容をそのままコピー 10 memcpy(&test_as_float, &test, sizeof(test_as_float));//メモリの内容をそのままコピー 11 printf("pi=3.14を整数型で出力\t%d\n", pi); 12 printf("pi_as_intを整数型で出力\t%d\n", pi_as_int); 13 printf("test=10を小数型で出力\t%f\n", test); 14 printf("test_as_floatを小数型で出力\t%f\n", test_as_float); 15 printf("test_as_floatを小数型で出力\t%g\n", test_as_float); 16 17 printf("pi=3.14を整数型で出力\t%d\n", (int)pi);//キャストして出力 18 printf("test=10を小数型で出力\t%f\n", (float)test);//キャストして出力 19 return 0; 20}
pi=3.14を整数型で出力 1374389535
pi_as_intを整数型で出力 1374389535
test=10を小数型で出力 0.000000
test_as_floatを小数型で出力 0.000000
test_as_floatを小数型で出力 1.4013e-44
pi=3.14を整数型で出力 3
test=10を小数型で出力 10.000000
投稿2017/07/20 14:55
総合スコア818
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
printf関数は引数をいくつでもとることができる特殊な関数です(可変長引数)。
printfは、
文字1個、整数2個、浮動小数点数3個、文字と整数1個ずつ、…
など、多種多様な引数をとることができます。これらすべてを含むことが可能な型は、ありません。なのでプロトタイプ宣言においては、引数とする型を明記しません。
int printf(const char*, ...);
では、関数を記述する側では、どのように引数を受けとるのか。printfの場合、最初の引数で、後続の引数がどのようになっているかを指定します。%dなら、int型、%fなら、doubleのように。
しかし、それはあくまで実装の話。利用側では、最初の引数に何が書いてあろうが、piならdouble型、testならint型を渡すようにコンパイルされます。
おかしな挙動になったのは、書式指定が誤っていたために、渡された変数の情報を正しく解釈できなかったからです。正しく解釈させたければ、書式指定に合うように明示的にキャストする必要があります。
以上、非常にかいつまんだおはなし。不正確な部分もありますが参考になりましたか?
投稿2017/07/20 13:33
総合スコア1720
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
コンパイルオプションで、printfの引数も見てくれるものがあったはず。
#/Wall
だったかな。
投稿2017/07/21 06:43
総合スコア204
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
#include<stdio.h> main() { double pi = 3.14; int test = 10; printf("pi=3.14を整数型で出力\t%d\n", (int)pi); printf("test=10を小数型で出力\t%lf\n", (double)test); return 0; }
これで、
pi=3.14を整数型で出力 3
test=10を小数型で出力 10.000000
お望みの結果が得られます。
暗黙的なキャストには、他の変数に代入した時に一定の規則の元値が変化します。
ええ〜〜と。
すぐには確認できないんですが、確か符号付き整数と符号なし整数の暗黙的キャストが一番複雑で、数式があったはずです。
すいません。間違っているかもしれません。
ただ暗黙的なキャストか明示的なキャストかの違いかと思います。
投稿2017/07/20 12:35
編集2017/07/20 12:44総合スコア651
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/07/20 13:17
2017/07/20 13:26 編集
2017/07/20 13:30
2017/07/20 13:33
2017/07/20 13:57
2017/07/20 14:28
2017/07/21 02:39
2017/07/21 08:34
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/07/21 05:33
2017/07/21 21:22