• ベストアンサー

書式制御'%d'と'%f'について

以下のようなソースがあります。 実行すると、異常な、という処理において、 printf関数で、int型を'%f'で、処理すると 0.000000になります。 また、double型を'%d'で、処理すると 0になります。 これは何故、0になるのでしょうか。 説明できるかた、よろしくお願いいたします。 include <stdio.h> void main(){  int i;  double d;  i=100;  d=1.0;  printf("i=%d\n",i); /* 正常なprintf関数 */  printf("d=%f\n",d); /* 正常なprintf関数 */  printf("i=%f\n",i); /* 異常なprintf関数 */  printf("d=%d\n",d); /* 異常なprintf関数 */  return; }

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

  • ベストアンサー
  • ultraCS
  • ベストアンサー率44% (3956/8947)
回答No.3

printfというのは関数であり、ステートメントではありません。この意味を理解していますか。 関数呼び出し規約を一度読んでみればどういう事が起こっているのかわかるでしょう(理解できなければ、勉強してください)。たしか、C&Rに書いてあったはずです。 で、具体的な解説、面倒なので、intel86限定で説明します。  printf("i=%f\n",i); /* 異常なprintf関数 */ では、printfを呼び出す際、"i=%f\n"のアドレスと、iの中身(処理系にもよるが2バイトが多いかな)をスタックに積んで、Printfを呼び出します。で、printfがどう動作するかというと、まず、書式のアドレスをスタックから取り出し、書式の解析を始め、それに従って、粛々と処理します。%fが出てきた時点で、スタックからfloatに相当する4バイトを取り出そうとします、しかし、ここでは、スタックには2バイトしか残っていません、で、ここはOSにもよりますが、stack emptyでエラーになるか、stack boundaryを破壊して不定の値を取り出すかになります。 floatにintを突っ込めば、ntの値が256以下なら、実質的には表示としてはfloatingのフォーマットにも寄りますがexponentが0(あるいは2~-128)ですから、0.0000になるのはわからない話ではありません。 また、doubleをintで処理した場合、2バイトだけ取り出してくるのですが、エンディアンにもよりますが、0になることはあり得ます。 いずれにしろ、これはプログラマとしてはやってはいけないことの一つです。理解するのは大切ですが、考えるだけ無駄でしょう。

参考URL:
w@
burbe
質問者

お礼

ありがとうございました。

その他の回答 (3)

  • ency
  • ベストアンサー率39% (93/238)
回答No.4

期待した動作をさせたいのなら、次のようにすればよいでしょう。 (修正前) printf("i=%f\n",i); /* 異常なprintf関数 */ printf("d=%d\n",d); /* 異常なprintf関数 */ ⇒ (修正後) printf( "i=%f\n", (double)i ); printf( "d=%d\n", (int)d ); 「未定義動作」はそもそも動作が保障されていないわけですから、たとえどのようなことが起こっても文句は言えない、ということです。 # printf() の double型の書式に "%lf" を使用するのも未定義だったような気がするけど、 # 結構よく見かけるんですよね。 # 明らかに scanf() の書式との混同なんだけど、たいていの処理系でそれなりに # 動いてしまうみたいですから。。。

burbe
質問者

お礼

ありがとうございました。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.2

「JIS X3010:2003の7.19.6.1 fprintf関数」では、 実引数の型が対応する変換指定に対して,正しくない場合,未定義とする. となっています。printfの場合も同様ですので、やはり未定義です。すなわち、そんな間違った使い方をした場合のことは何一つケアしていないので、成り行きに任せた結果が、たまたま > printf関数で、int型を'%f'で、処理すると > 0.000000になります。 > また、double型を'%d'で、処理すると > 0になります。 のようになっただけです。

burbe
質問者

お礼

ありがとうございました。

  • phoenix343
  • ベストアンサー率15% (296/1946)
回答No.1

整数型と浮動小数型の違いですね。double型は上位何ビットかを、指数にあてていて、そのまま変換はできません。 通常の代入文ではコンパイルするときに型変換してくれますが、printf文の引数として渡すとそうはいかず整数型のまま浮動小数型に入れるので違う値になります。 こんな説明で、分かるかな?

burbe
質問者

お礼

ありがとうございました。

関連するQ&A