#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()
呼び出されます。
技術的には何もありません、各ライブラリ独自の実装、およびので、勉強しようとするあなたの方法は、 printf
printf
あなたが何をしているか実行しての行動は、多くの使用であることを行っていません。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バイトはdouble
0であることがわかりました。これが、0
printf
。これが、呼び出しの出力としてられたあります。
より興味深い結果を得るには、プログラムを少し変更します。
#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
です。 printf
with %d
はint
42 の引数を取り、%d
2番目の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など)を使用するだけです。