C中的长双

时间:2009-11-22 15:36:05

标签: c long-double

我一直在阅读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。但是我仍然无法理解为什么我得到了双 abet 值,而不是我在 Cygwin Ubuntu上运行它时得到的值 iDeneb 大致是

-1950228512509697486020297654959439872418023994430148306244153100897726713609
013030397828640261329800797420159101801613476402327600937901161313172717568.0
00000 can be written 2.725000e+02

有什么想法吗?

5 个答案:

答案 0 :(得分:7)

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

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

答案 1 :(得分:4)

C Standard Libraryprintf()函数是 variadic function 的示例,可以使用不同数量的参数。 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并打印与该特定位模式对应的值。但是,正如标准所述,它可以做任何它喜欢的事情。

答案 2 :(得分: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;
}

输出:

The output; transcript below

32000.000000 can be written 3.200000e+04
2140000000.000000 can be written 2.140000e+09
0.000053 can be written 5.320000E-05

答案 3 :(得分:3)

也许64位ABI的不同之处在于printf在与%LF参数完全不同的地方查找%f参数。

尝试查看程序集输出(gcc -S)以查看是否为真。

答案 4 :(得分: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