关于C中的转换说明符

时间:2016-07-18 02:31:18

标签: c format-specifiers

我对C中的转换说明符有疑问。

如果我使用%lf%Lf代替%f,则在第5句中,不会发生错误。但是,如果我使用%f,为什么会发生错误?

#include <stdio.h>

int main(void)
{
    long double num;
    printf("value: ");
    scanf("%f",&num);  // If I use %lf or %Lf instead of %f, no error occurs. 
    printf("value: %f \n",num);
}

2 个答案:

答案 0 :(得分:6)

%f旨在用于阅读float,而不是doublelong double

%lf旨在用于阅读double s。

%Lf旨在用于阅读long double s。

如果您的程序在变量类型为%lf时与long double一起使用,则只是巧合。它的工作原理可能是因为sizeof(double)与您平台上的sizeof(long double)相同。从理论上讲,这是不确定的行为。

答案 1 :(得分:0)

在FreeBSD系统(顺便提一下是POSIX)上查看printf(3)的手册页时,我得到以下内容:

  

以下长度修饰符适用于aAeEfF,{{1 }},            或g转化:

G

我使用了32位浮点数据类型的转换。但问题在于,原因是因为不同的浮点格式具有不同的大小, Modifier a, A, e, E, f, F, g, G l (ell) double (ignored, same behavior as without it) L long double 函数需要知道它是哪一个,以便它可以正确地进行转换。在浮点数上使用printf可能会导致分段错误,因为转换正在访问变量外部的数据,因此您会得到未定义的行为。

  • float:32位
  • double:64位
  • long double:80位

现在对于%Lf,实际大小由平台和实现定义。 80位是10个字节,但是没有填充,它不能完全适合32位对齐。因此,大多数实现使用96位或128位(分别为12个字节或16个字节)来设置对齐。

这里要小心,因为它可能需要128位并不意味着它是long double(如果使用gcc或clang)。至少有一个平台指定__float128表示long double(我认为是SunOS),但它是用软件实现的,速度很慢。此外,一些编译器(Microsoft和Intel会想到)__float128 = long double,除非您在命令行上指定了一个开关。