#include <stdio.h>
int main() {
float a = 1234.5f;
printf("%d\n", a);
return 0;
}
表示します0!! そんなことがあるものか?理由は何ですか?
私は意図的に入れている%d中でprintfの挙動を研究するためのステートメントprintf。
回答:
それ%dはを期待しているためですintが、フロートを提供しました。
%e/ %f/ %gを使用して、フロートを印刷します。
0が出力される理由:doubleに送信する前に、浮動小数点数がに変換されprintfます。リトルエンディアンの二重表現の数値1234.5は
00 00 00 00 00 4A 93 40
A %dは32ビット整数を消費するため、ゼロが出力されます。(テストとして、printf("%d, %d\n", 1234.5f);出力を得ることができます0, 1083394560。)
floatがに変換される理由についてdoubleはint printf(const char*, ...)、printfのプロトタイプが6.5.2.2/7から、
関数プロトタイプ宣言子の省略記号表記により、最後に宣言されたパラメーターの後で引数の型変換が停止します。デフォルトの引数の昇格は、末尾の引数に対して実行されます。
そして6.5.2.2/6から、
呼び出された関数を表す式の型がプロトタイプを含まない場合、整数の昇格が各引数で実行され、型の
floatある引数がに昇格されdoubleます。これらは、デフォルトの引数プロモーションと呼ばれます。
(これを見つけてくれてAlokに感謝します。)
printf可変引数関数であり、標準は、可変長の機能のために、と言うfloatに変換されてdouble渡す前に。
printf()呼び出されます。
技術的には何もありません、各ライブラリ独自の実装、およびので、勉強しようとするあなたの方法は、 printfprintfあなたが何をしているか実行しての行動は、多くの使用であることを行っていません。printfシステムでのの動作を調べようとしている可能性があります。その場合は、ドキュメントを読み、printfライブラリで使用できるかどうかのソースコードを確認する必要があります。
たとえば、私のMacbookでは、出力を取得します 1606416304、プログラムでています。
そうは言っても、float可変個の関数にa をfloat渡すと、はdouble。したがって、プログラムはaとして宣言したのと同じdoubleです。
のバイトを調べるには double SOの最近の質問に対するこの回答を見ることができます。
それをしましょう:
#include <stdio.h>
int main(void)
{
double a = 1234.5f;
unsigned char *p = (unsigned char *)&a;
size_t i;
printf("size of double: %zu, int: %zu\n", sizeof(double), sizeof(int));
for (i=0; i < sizeof a; ++i)
printf("%02x ", p[i]);
putchar('\n');
return 0;
}
上記のプログラムを実行すると、次のようになります。
size of double: 8, int: 4
00 00 00 00 00 4a 93 40
したがって、最初の4バイトはdouble0であることがわかりました。これが、0printf。これが、呼び出しの出力としてられたあります。
より興味深い結果を得るには、プログラムを少し変更します。
#include <stdio.h>
int main(void)
{
double a = 1234.5f;
int b = 42;
printf("%d %d\n", a, b);
return 0;
}
Macbookで上記のプログラムを実行すると、次のようになります。
42 1606416384
Linuxマシンで同じプログラムを使用すると、次のようになります。
0 1083394560
int引数が引数とは異なるレジスターで渡されるためdoubleです。 printfwith %dはint42 の引数を取り、%d2番目のint引数がないため、2番目はおそらくジャンクを出力します。
%d指定子は伝えますprintf整数を期待します。したがって、floatの最初の4バイト(またはプラットフォームによっては2バイト)は整数として解釈されます。それらが偶然ゼロの場合、ゼロが出力されます
1234.5のバイナリ表現は次のようなものです
1.00110100101 * 2^10 (exponent is decimal ...)
float実際にIEEE754 double値として表現するCコンパイラーでは、バイトは(私がミスをしなかった場合)
01000000 10010011 01001010 00000000 00000000 00000000 00000000 00000000
エンディアンがほとんどない(つまり、最下位バイトが最初に来る)Intel(x86)システムでは、このバイトシーケンスが逆になり、最初の4バイトがゼロになります。つまり、何がprintf印刷されるのか...
IEEE 754による浮動小数点表現については、このWikipediaの記事を参照してください。
適切なフォーマット指定子(%d、%f、%sなど)と関連するデータ型(int、float、stringなど)を使用するだけです。