1

私の知る限り、出力は 3.14,3.14,3.14 と 256,256,256 のようになるはずですよね? しかし、これは異なる出力を生成します。誰でもこれを案内して、なぜこれが起こるのか教えてもらえますか?

    main()
    {
     float a = 3.14;
     int b = 256;
     char *p, *p1;
     p = (char *) &a;
     p1 = (char *) &b;
     printf("\nFLOAT:");
     printf("\nValue of *p=%f",*p);
     printf("\nValue of a=%f",a);
     printf("\nValue of *p=%f",*p);
     printf("\n\nINTEGER:");
     printf("\nValue of *p1=%d",*p1);
     printf("\nValue of b=%d",b);
     printf("\nValue of *p1=%d",*p1);
    }

    Output:
    FLOAT:
    Value of *p=0.000000
    Value of a=3.140000
    Value of *p=3.140001

    INTEGER:
    Value of *p1=0
    Value of b=256
    Value of *p1=0
4

4 に答える 4

5

式の*pタイプはcharです。フォーマット指定子%fには、タイプの引数が必要floatです。のような可変個引数関数に間違った型の引数を渡すと、printf未定義動作が呼び出されます。

于 2012-08-20T01:41:05.477 に答える
2

浮動小数点型と整数型が混在する可変個引数関数の動作が定義されていないことを考えると、あなたが行った回答 (http://ideone.com/RG4uq) とは少し異なる回答が得られました。

これが何が起こっているかです。メモリがアドレス 0x50000000、32 ビット マシン、リトル エンディアンで始まると仮定します。

50000000  c3  f5  48  40   (a)
50000004  00  01  00  00   (b)
50000008  00  00  00  50   (p)
5000000c  04  00  00  50   (p1)

a の型は float、b の型は int、p の型は char*、p1 の型は char* です。

整数については、

  • print p1 as an int ==> *p1は、アドレス 50000004 のバイトであり、0 であるため、0 が出力されます。
  • print b as an int ==>bそれはintであるため、明らかに256です。
  • print p1 as an int ==> *p1はアドレス 50000004 のバイトで、これは 0 であるため、0 が出力されます (以前と同様)。

リトルエンディアンのマシンではp1[1]、整数として出力しようとしても 1 が表示されます (興味深いですね。http://ideone.com/daS6dを参照してください)。

フロートの場合は事情が異なります。多くのプロセッサー (x86-64 など) では、パラメーターはレジスターで渡されます。あなたはprintf3回電話をかけています。印刷されるものが来るたびにxmm0(x86-64を想定)。ただし、最初に*pchar を印刷しようとすると、も渡されないxmm0(*pが渡される%edi) ため、そこにあったがらくたが印刷されることに注意してください (0、または 0.0234892374 など)。しかし次に、実際のfloatを渡してxmm03.14 を出力します。しかし、3 番目の printf に取り掛かると、再び何も渡されません (これ*pは char であるため)。xmm0? そうです 3.14. それはおそらく別のものだったかもしれませんが、おそらく変わっていません。:)

于 2012-08-20T02:18:30.093 に答える
0

float* と char* のサイズが異なるため、期待どおりに動作しません。それらを変換すると、表現の精度が犠牲になる可能性があります。

于 2012-08-20T01:45:17.190 に答える
0

char簡単に言えば、型をprintfに書式指定子を使用して渡すと、未定義の動作が呼び出されるため、特に何も期待し%fないでください。

長い答えは実装に依存しますが、次に示すのは、プラットフォームで発生する可能性があることに関する私の観察です。値を出力するように要求printfするとdouble(%fフォーマット指定子と同様)、スタックから次のバイトを読み取り、sizeof(double)それを浮動小数点値として解釈して出力します。最初のprintf呼び出しでは、新しいスタック フレームが初めて生成されcharます。実際に渡されたビットを形成する後のスタック上のデータは、ゼロの浮動小数点値に相当します。への 2 回目の呼び出しprintfで、新しいスタック フレームが生成され、おそらく最初の呼び出しと同じスペースが上書きされます。この場合、完全なdouble値が存在し、期待どおりに出力されます。関数が戻ると、スタック フレームは「破棄」されます。効率の問題として、スタック フレームは通常、関数が返されたときに内容が残っているときにゼロにされません。への 3 回目の呼び出しではprintf、再び 1 バイトを渡しますが、バイトを浮動小数点値としてprintf解釈するように要求します。sizeof(double)前の呼び出しから へのスタック フレームには、前の呼び出しから渡されprintfた値が含まれており、doubleこれらのバイトの 1 つが新しい引数からのバイトで上書きされ、値が出力されます。

printf2回目の電話を次のように変更すると:

printf("\nValue of a=%f", 1.234);

印刷への3回目の呼び出しprintf(私のシステム上):

Value of *p=1.234000

上記のロジックを検証しているようです。

要約すると、printf実際に関数に渡したよりも多くのデータをスタックから読み取るように要求しているため、結果は未定義です。あなたの場合、読み取られたデータは、特定のプラットフォームで得られる結果を説明する以前の呼び出しの残りです。(Ray が指摘しているように、引数が渡される実際の方法は、実装に依存するため、異なる可能性があります。一部のシステムは、値をレジスターで渡しますが、ポイントは同じままです。)

于 2012-08-20T02:07:39.443 に答える