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. 但是我仍然不明白为什么我得到了 doubleabet值而不是我在CygwinUbuntuiDeneb上运行它时得到的值,这大致是

-1950228512509697486020297654959439872418023994430148306244153100897726713609
013030397828640261329800797420159101801613476402327600937901161313172717568.0
00000 can be written 2.725000e+02

有任何想法吗?

4

5 回答 5

8

尝试查看 OSX 上的可变参数调用约定,这可能会解释它。

我猜编译器会传递long double堆栈(或 FPU 寄存器)中的第一个double参数,以及 CPU 寄存器(或堆栈)中的第一个参数。无论哪种方式,它们都在不同的地方通过。因此,当进行第三次调用时,第二次调用的值仍然存在(并且被调用者捡起它)。但这只是一个猜测。

于 2009-11-22T15:50:21.653 回答
4

C 标准库的函数是可变参数函数printf()一个示例,它可以采用不同数量的参数。C 语言实现这一点的方式,被调用函数必须知道以何种顺序传递的参数类型,以便正确解释它们。这就是您传递格式字符串的原因,以便正确理解它必须打印的数据。printf()

如果可变参数函数错误地解释了传递给它的参数,C 标准会指定行为未定义,即任何事情都可能发生(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为 adouble并打印与该特定位模式相对应的值。但是,正如标准所述,它可以为所欲为。

于 2009-11-22T16:13:49.000 回答
4

使用说明符%LF作为long 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,就像你一样,我注意到了同样的事情。看看我如何更改第三个 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 回答