2011-09-20 11 views
14

私はC Programming Language, 2nd Editionを読んでCを学ぼうとしています。私はいくつかのプログラミング経験を持っていますが、C.%dをprintfで使用すると、float変数はどうなりますか?

と私は現在、第1章では、私は次のコードを持っていない:


float f; 
    for (f = 0.0; f <= 3; f += 1.1) 
     printf("A: %3f B: %6.2f\n", f, f + 0.15); 

をそれは出力を印刷します:

A: 0.000000 B: 0.15 
A: 1.100000 B: 1.25 
A: 2.200000 B: 2.35 

よく見えます。次のように


は今、私はprintfのを変更:

printf("A: %3d B: %6.2f\n", f, f + 0.15); 

新しい出力がここで何が起こっている

A: 0 B: 0.00 
A: -1610612736 B: 0.00 
A: -1610612736 B: -625777476808257557292155887552002761191109083510753486844893290688350183831589633800863219712.00 

のですか?私は%dを使用しているので、floatがintに変換されることを期待しますが、それは起こったことではありません。また、なぜBの値もうまくいかなかったのでしょうか?ここに何が起こったの?

+2

あなたはそれをintに変換するように頼んだわけではありません。ゴミ入れ、ゴミ出し。 –

答えて

15

あなたは呼ば:

printf("A: %3d B: %6.2f\n", f, f + 0.15); 

Cが自動的にそれが(doublefloat値をされて変換し、 int printf(const char *fmt, ...);のような可変の引数をとる関数を呼び出すと標準的な変換が行われます)。議論のために、sizeof(int)は4で、sizeof(double)は8であると仮定します(例外はありますが、それらはあまりありません)。

したがって、呼び出しはスタックにポインタをプッシュし、さらにfの場合は8バイト、もう1つの場合はf + 0.15の場合は8バイトの倍数になります。フォーマット文字列を処理するとき、%dprintf()に、フォーマット文字列の後に4バイトのintをスタックにプッシュしたことを伝えます。それはあなたがしたことではないので、あなたは未定義の動作を呼び出しました。次に起こることは、C標準に従ってOKです。

しかし、最も可能性の高い実装では、blithely 4バイトを読み込んで、intのように印刷します(真実を伝えることができます)。それから、それは%6.2fフォーマットに渡ります。スタックから8バイトを読み取ってdoubleとして読み込みます。これにより、誤整列アクセスのメモリフォールトが発生する可能性があります(これは、SPARCなどの8バイト境界にdoubleを配置する必要がある64ビットマシンを必要とします)か、または4バイトを読み込みますfと、f + 0.15からの4バイトを組み合わせて、予期しないdoubleの値を作成します。

+0

素晴らしい答えですので、 'printf(" A:%d%d B:%6.2 "、...'と間違ったA値を取得しますが、Bは影響を受けません –

+1

かなり考えられる仮定の数が多いこの動作は厳密には定義されていませんが、実際にはyesです。 –

8

Printfはあなたが指摘したようにあなたが指しているメモリを扱います。コンバージョンは起こりません。浮動小数点を表すメモリをintとして扱います。 2つは別々に格納されるため、基本的には乱数を得ることができます。

あなたは整数として出力し、あなたのフロートをしたい場合は、あなたが最初にそれをキャストする必要があります。

printf("A: %3d B: %6.2f\n", (int)f, f + 0.15); 
+1

さて、それは理にかなっています。私はそれをint型にキャストしなかったので、fの値は変更されましたか?そうでなければ、printfの2番目の部分が%6.2fを使用していますので、atleastが正しい値を持っている必要がありますか? – Gollum

関連する問題