6

私はC Primer Plusの本を読んでいて、この例にたどり着きました

#include <stdio.h>
int main(void)
{
    float aboat = 32000.0;
    double abet = 2.14e9;
    long double dip = 5.32e-5;

    printf("%f can be written %e\n", aboat, aboat);
    printf("%f can be written %e\n", abet, abet);
    printf("%f can be written %e\n", dip, dip);

    return 0;
}

Macbook でこれを実行した後、次の出力に非常にショックを受けました。

32000.000000 can be written 3.200000e+04
2140000000.000000 can be written 2.140000e+09
2140000000.000000 can be written 2.140000e+09

そこで、よく調べてみると、long double を表示する正しい形式は を使用することであることがわかりました%Lfただし、 CygwinUbuntu、およびiDenebabet実行したときに取得した値ではなく、 double 値を取得した理由をまだ理解できません。

-1950228512509697486020297654959439872418023994430148306244153100897726713609
013030397828640261329800797420159101801613476402327600937901161313172717568.0
00000 can be written 2.725000e+02

何か案は?

4

5 に答える 5

8

OSX での varargs 呼び出し規約を調べてみてください。

私は、コンパイラがlong doubleスタック (または FPU レジスタ) の最初のdoubleパラメータと、CPU レジスタ (またはスタック) の最初のパラメータを渡すと推測しています。いずれにせよ、それらはさまざまな場所で渡されます。そのため、3 番目の呼び出しが行われると、2 番目の呼び出しの値がまだ残っています (呼び出し先がそれを取得します)。しかし、それは単なる推測です。

于 2009-11-22T15:50:21.653 に答える
4

C 標準ライブラリの関数は、さまざまな数の引数を取ることができる可変引数関数printf()例です。C言語がこれを実装する方法では、呼び出された関数、引数を正しく解釈できるように、どのタイプの引数がどの順序で渡されたかを認識している必要があります。これが、フォーマット文字列を渡す理由です。これにより、印刷する必要があるデータを正しく理解できます。printf()

可変引数関数が渡された引数を正しく解釈しない場合、C 標準では動作がundefinedであると指定されています。つまり、何でも起こり得る (C89 標準 4.8.1.2)。あなたの場合、一致しないフォーマットと値を に渡しているところprintf()、それが起こっています。ただし、まともなコンパイラを使用していて、警告レベルが適切なレベルに達している場合は、コンパイル時にこれについて警告する必要があります。たとえば、Cygwin では次のようになります。

$ make go
cc -g -W -Wall -Wwrite-strings -ansi -pedantic    go.c   -o go
go.c: In function `main':
go.c:10: warning: double format, long double arg (arg 2)
go.c:10: warning: double format, long double arg (arg 3)
go.c:10: warning: double format, long double arg (arg 2)
go.c:10: warning: double format, long double arg (arg 3)
$ 

表示されているものを具体的に取得する理由については、特定の実装によって異なります。実際には、 の特定の実装が のprintf()前半をlong doubleとして解釈し、doubleその特定のビット パターンに対応する値を出力している可能性があります。ただし、標準が述べているように、好きなことを何でもできます。

于 2009-11-22T16:13:49.000 に答える
4

または%LFlong double代わりに指定子を使用します。は常に とは異なる意味を持ちます。%lf%f%LF%lf

#include <stdio.h>
int main(void)
{
    float aboat = 32000.0;
    double abet = 2.14e9;
    long double  dip = 5.32e-5L;

    printf("%f can be written %e\n", aboat, aboat);
    printf("%f can be written %e\n", abet, abet);
    printf("%LF can be written %LE\n", dip, dip);

    return 0;
}

出力:

出力;  以下のトランスクリプト

32000.000000 can be written 3.200000e+04
2140000000.000000 can be written 2.140000e+09
0.000053 can be written 5.320000E-05
于 2015-03-11T05:28:52.600 に答える
3

おそらく、64 ビット ABI は、printf が %LF 引数とはまったく異なる場所で %f 引数を探すという点で異なっています。

アセンブリの出力 ( gcc -S) を調べて、これが正しいかどうかを確認してください。

于 2009-11-22T15:56:33.293 に答える
1

私はC Primer Plusを読んでいて、あなたと同じことに気づきました。3 番目の printf ステートメントの書式指定子をどのように変更したかを確認してください。

#include <stdio.h>
#include <inttypes.h>

int main(void){

    float aboat = 320000.0;
    double abet = 2.214e9;
    long double dip = 5.32e-5;

    printf("%f can be written %e\n", aboat, aboat);
    printf("%f can be written %e\n", abet, abet);
    printf("%Lf can be written %Le\n", dip, dip);

    return 0;
}

書式指定子を変更した後の結果

320000.000000 can be written 3.200000e+05
2214000000.000000 can be written 2.214000e+09
0.000053 can be written 5.320000e-05
于 2010-06-06T21:43:08.343 に答える