Scanf/Printf双精度变量C

49

假设我在C语言中有以下代码:

double var;
scanf("%lf", &var);
printf("%lf", var);
printf("%f", var);

它从标准输入读取变量“ var”,然后在标准输出中两次打印“ var”。 我知道这是如何从标准输入读取双精度变量的,但我的问题是:

  1. 为什么可以使用%lf打印双精度?
  2. 为什么可以使用%f打印双精度?
  3. 哪个更好,更正确?

5
printf 函数中它们是相同的。 - Maroun
scanf 接受指针,无法提升,但 printf 接受值,可以提升。就打印而言,我可能会使用 %lf,因为对于任何阅读您的代码的人来说,这更清晰。 - robbie_c
3个回答

62

对于变长参数函数(例如printfscanf),参数会被提升,比如较小的整数类型会被提升为intfloat 会被提升为double

scanf 接受指针类型的参数,因此提升规则不起作用。它必须使用 %f 来读取 float* 类型的值,使用 %lf 来读取 double* 类型的值。

printf 永远不会看到 float 类型的参数,因为 float 总是会被提升为 double。格式说明符是 %f。但是,C99 同时规定在 printf 中,%lf%f 是相同的:

C99 §7.19.6.1 函数 fprintf

l (小写字母 L)表示后面的 dioux、或 X 转换说明符应用于一个 long intunsigned long int 类型的参数;表示后面的 n 转换说明符应用于一个 long int 类型的指针;表示后面的 c 转换说明符应用于一个 wint_t 类型的参数;表示后面的 s 转换说明符应用于一个 wchar_t 类型的指针;或对后面的 aAeEfFg、或 G 转换说明符没有影响。


13

当一个浮点数(float)被传递给 printf 函数时,它会自动转换为双精度浮点数(double)。这是“默认参数提升”(default argument promotions)的一部分,该机制适用于具有可变参数列表(包含 ...)的函数,主要是由于历史原因。因此,“自然”的浮点数格式规定符 %f 必须与 double 类型的参数兼容。所以对于 printf 函数,%f%lf 的规定符是相同的;它们都接收一个双精度浮点数类型的值。

在调用 scanf 函数时,传递的是指针而不是直接的值。指向 float 类型的指针不会被转换为指向 double 类型的指针(这是无法实现的,因为当你改变指针类型时,指向的对象不能改变)。因此,在使用 scanf 函数时,%f 的参数必须是指向 float 类型的指针,而 %lf 的参数必须是指向 double 类型的指针。


6
据我所读的手册页面,scanf函数中的“l”长度修饰符表示(在浮点数的情况下)参数的类型为double而不是float,因此您可以使用“lf、le、lg”。
至于打印方面,官方手册表示“l”仅适用于整数类型。因此,在某些系统或标准上可能不受支持。例如,使用“gcc -Wall -Wextra -pedantic”编译时会出现以下错误消息。
a.c:6:1: warning: ISO C90 does not support the ‘%lf’ gnu_printf format [-Wformat=]

所以您可能需要仔细检查您的标准是否支持该语法。

总之,我会建议您使用“%lf”进行阅读,并使用“%f”进行打印。


如果使用C99和C11规范作为“官方”,它们会说:“...对于后续的a、A、e、E、f、F、g或G转换说明符没有影响。” - chux - Reinstate Monica
1
什么是“手册(the manual)”?没有标题和版本信息,这不是一个有用的参考资料。此外,当前年份是2013年,因此应该避免使用1990年的软件规格,因为现在已经有更现代化的版本可用。 - Eric Postpischil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接