88
#include <stdio.h>

int main() {
    float a = 1234.5f;
    printf("%d\n", a);
    return 0;
}

0!!が表示されます。そんなことがあるものか?理由は何ですか?


の振る舞いを研究するために意図的にステートメントに を入れ%dましprintfprintf

4

13 に答える 13

239

これ%dは、 が期待しているintが、float を提供したためです。

%e/ %f/を使用%gして float を出力します。


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と、printf のプロトタイプが であるint printf(const char*, ...)ため、6.5.2.2/7 から、

関数プロトタイプ宣言子の省略記号表記により、最後に宣言されたパラメーターの後で引数の型変換が停止します。デフォルトの引数昇格は、末尾の引数に対して実行されます。

そして6.5.2.2/6から、

呼び出された関数を示す式がプロトタイプを含まない型を持つ場合、各引数に対して整数昇格が実行され、型を持つ引数floatは に昇格されdoubleます。これらはデフォルト引数のプロモーションと呼ばれます。

(これを見つけてくれたAlokに感謝します。)

于 2010-03-04T08:23:34.980 に答える
45

技術的に言えば はなく printf各ライブラリは独自に実装しているため、自分printfがしていることを実行して の動作を研究しようとする方法はあまり役に立ちません。システムでの の動作を調べようとしている可能性がありprintfます。その場合は、ドキュメントを読み、ソース コードをprintf調べて、ライブラリで利用できるかどうかを確認してください。

たとえば、私の Macbook では、1606416304あなたのプログラムで出力を取得します。

そうは言っても、floata を可変引数関数に渡すと、floatは として渡されますdouble。したがって、プログラムは として宣言aしたのと同じdoubleです。

a のバイトを調べるには、SO に関する最近の質問に対するこの回答doubleを参照してください。

それをしましょう:

#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
于 2010-03-04T08:45:26.247 に答える
20

%d指定子はprintf、整数を期待するように指示します。したがって、float の最初の 4 (プラットフォームによっては 2) バイトは整数として解釈されます。それらがたまたまゼロの場合、ゼロが出力されます

1234.5 のバイナリ表現は次のようになります。

1.00110100101 * 2^10 (exponent is decimal ...)

実際に IEEE754 double 値として表す C コンパイラを使用するfloatと、バイトは次のようになります (間違いがなければ)

01000000 10010011 01001010 00000000 00000000 00000000 00000000 00000000

エンディアンがほとんどない (つまり、最下位バイトが最初に来る) Intel (x86) システムでは、このバイト シーケンスが逆になり、最初の 4 バイトがゼロになります。つまり、printf出力されるものは...

IEEE754 に従った浮動小数点表現については、このウィキペディアの記事を参照してください。

于 2010-03-04T08:20:32.883 に答える
8

未定義の動作を呼び出したためです。パラメーターの型について嘘をついて printf() メソッドの契約に違反したため、コンパイラーは好きなことを自由に行うことができます。プログラムに「dksjalk is a ninyhead!!!」という出力をさせることができます。技術的にはまだ正しいでしょう。

于 2010-03-04T08:21:37.233 に答える
7

これは、フロートがバイナリで表現されているためです。整数に変換すると、0 のままになります。

于 2010-03-04T08:19:39.717 に答える
5

その理由は、それprintf()がかなりばかげた機能だからです。タイプはまったくチェックしません。最初の引数が であると言う場合int(これは で言っていることです%d)、それはあなたを信じて、 に必要なバイトだけを取りますint。この場合、マシンが 4 バイトintと 8バイトを使用すると仮定するとdouble( はinside にfloat変換されます)、 の最初の 4 バイトはゼロになり、これが出力されます。doubleprintf()a

于 2010-03-04T08:21:26.387 に答える
3

float を integer に自動的に変換しません。どちらもストレージの形式が異なるためです。したがって、変換する場合は (int) 型キャストを使用します。

#include <stdio.h>

int main() {
    float a = 1234.5f;
    printf("%d\n", (int)a);
    return 0;
}
于 2010-03-04T08:22:41.287 に答える
2

C++ でタグ付けしたので、このコードはおそらく期待どおりに変換されます。

#include <iostream.h>

int main() {
    float a = 1234.5f;
    std::cout << a << " " << (int)a << "\n";
    return 0;
}

出力:

1234.5 1234
于 2010-03-04T08:25:00.487 に答える
1

関連するデータ型 (int、float、string など) で適切な書式指定子 (%d、%f、%s など) を使用するだけです。

于 2010-03-04T10:14:07.863 に答える
1

%d小数です

%fフロートです

これらの詳細については、こちらを参照してください。

浮動小数点数と整数の表現が異なるため、0 を取得しています。

于 2010-03-04T08:19:28.440 に答える
0

何かを印刷する必要があったので、0 を印刷しました。C では 0 が他のすべてであることを思い出してください。

于 2010-03-04T09:12:11.333 に答える
0

整数ではありません。を使ってみてください%f

于 2010-03-04T08:17:19.583 に答える
0

%d ではなく %f が必要です

于 2010-03-04T08:18:05.680 に答える