我在一本C书的C示例中看到过这两个参数,但作者没有详细说明两者之间的区别。我知道%f指定了一个float应该取代它的位置。我试着查了一下,但很难找到一个解释。%lf怎么样?
%f
float
%lf
nvbavucw1#
简短的回答是,它对printf没有影响,并表示在scanf中使用float或double。对于printf,类型为float的参数被提升为double,因此%f和%lf都用于double。对于scanf,应该使用%f作为float,%lf作为double。我们当中的语言律师的更多细节如下:在printf系列中,%f和%lf之间没有区别。ISO C标准(其中的所有参考文献均来自C11),第7.21.6.1 The fprintf function节,第/7段规定,对于l修饰符(我强调):指定以下d、i、o、u、x或X转换说明符应用于long int或unsigned long int参数;下面的n转换说明符应用于指向long int参数的指针;以下c转换说明符适用于wint_t参数;下面的s转换说明符应用于指向wchar_t参数的指针;或对以下a、A、e、E、f、F、g或G转换说明符无效。它不需要修改f说明符的原因是因为该说明符 already 表示double,来自同一节的段落/8,其中列出了%f说明符的类型:表示浮点数的double参数转换为十进制表示法这与函数原型中椭圆后面的参数受到默认参数提升的影响有关,如6.5.2.2 Function calls节,/7段:函数原型声明符中的省略号表示法会导致参数类型转换在最后一个声明的参数之后停止。默认参数升级是对尾随参数执行的。由于printf(以及整个类似printf的函数家族)使用省略符号声明为int printf(const char * restrict format, ...);,因此该规则适用于此处。默认参数提升在第6.5.2.2 Function calls节第/6段中介绍:如果表示被调用函数的表达式的类型不包括原型,则对每个参数执行整数提升,并且类型为float的参数被提升为double。这些称为默认参数提升。对于scanf系列,它要求使用double而不是float。截面7.21.6.2 The fscanf function /11:指定以下d、i、o、u、x、X或n转换说明符应用于类型指针指向long int或unsigned long int的参数;**以下a、A、e、E、f、F、g或G转换说明符适用于类型指针指向double的参数;**或以下c、s或[转换说明符应用于类型指针指向wchar_t的参数。这修改了该节的/12段落,该段落指出,对于%f:匹配可选带符号浮点数、无穷大或NaN,其格式与strtod函数主题序列的预期格式相同。相应的参数应该是一个指向浮点数的指针。
printf
scanf
double
7.21.6.1 The fprintf function
/7
l
d
i
o
u
x
X
long int
unsigned long int
n
c
wint_t
s
wchar_t
a
A
e
E
f
F
g
G
/8
6.5.2.2 Function calls
int printf(const char * restrict format, ...);
/6
7.21.6.2 The fscanf function /11
[
/12
NaN
strtod
qltillow2#
对于scanf,%f读入float,%lf读入double。对于printf:在C99和更高版本中,它们都是相同的,它们打印float或double。在C89中,%lf导致了未定义的行为,尽管将其视为%f是一个常见的扩展。在printf中,一个说明符可以用于两个不同的类型的原因是因为 default参数promotions; float类型的参数在用于调用函数且不匹配函数原型中的参数时提升为double。所以printf在任何情况下都只能看到double。
9udxz4iz3#
对于使用printf函数族的输出,%f和%lf说明符的含义相同;忽略L。两者都需要一个对应的double类型的参数,但是float类型的参数会升级为double,这就是为什么float类型没有单独的说明符。(此提升仅适用于printf等变元函数,以及没有原型声明的函数,而不适用于一般的函数调用。)对于类型long double,正确的格式说明符是%Lf。对于使用scanf函数族的输入,浮点格式说明符为%f、%lf和%Lf。它们分别需要指向float、double和long double类型的对象的指针。(没有float-to-double提升,因为参数是指针。一个float值可以提升为double,但是一个float* 指针不能提升为double*,因为指针必须指向一个实际的float对象。但是在使用scanf函数时要小心,要使用数字输入。没有定义溢出检查,如果输入超出了类型的范围,则程序的行为未定义。为了安全起见,将输入读入字符串,然后使用类似strtod的方法将其转换为数值。(请参阅文档以了解如何检测错误。)
moiiocjp4#
%lf中的宽度修饰符被printf()优雅地忽略。或者,更准确地说,%f需要一个double - varargs将始终将float参数提升为double。
4条答案
按热度按时间nvbavucw1#
简短的回答是,它对
printf
没有影响,并表示在scanf
中使用float
或double
。对于
printf
,类型为float
的参数被提升为double
,因此%f
和%lf
都用于double
。对于scanf
,应该使用%f
作为float
,%lf
作为double
。我们当中的语言律师的更多细节如下:
在
printf
系列中,%f
和%lf
之间没有区别。ISO C标准(其中的所有参考文献均来自C11),第7.21.6.1 The fprintf function
节,第/7
段规定,对于l
修饰符(我强调):指定以下
d
、i
、o
、u
、x
或X
转换说明符应用于long int
或unsigned long int
参数;下面的n
转换说明符应用于指向long int
参数的指针;以下c
转换说明符适用于wint_t
参数;下面的s
转换说明符应用于指向wchar_t
参数的指针;或对以下a
、A
、e
、E
、f
、F
、g
或G
转换说明符无效。它不需要修改
f
说明符的原因是因为该说明符 already 表示double
,来自同一节的段落/8
,其中列出了%f
说明符的类型:表示浮点数的
double
参数转换为十进制表示法这与函数原型中椭圆后面的参数受到默认参数提升的影响有关,如
6.5.2.2 Function calls
节,/7
段:函数原型声明符中的省略号表示法会导致参数类型转换在最后一个声明的参数之后停止。默认参数升级是对尾随参数执行的。
由于
printf
(以及整个类似printf
的函数家族)使用省略符号声明为int printf(const char * restrict format, ...);
,因此该规则适用于此处。默认参数提升在第6.5.2.2 Function calls
节第/6
段中介绍:如果表示被调用函数的表达式的类型不包括原型,则对每个参数执行整数提升,并且类型为
float
的参数被提升为double
。这些称为默认参数提升。对于
scanf
系列,它要求使用double
而不是float
。截面7.21.6.2 The fscanf function /11
:指定以下
d
、i
、o
、u
、x
、X
或n
转换说明符应用于类型指针指向long int
或unsigned long int
的参数;**以下a
、A
、e
、E
、f
、F
、g
或G
转换说明符适用于类型指针指向double
的参数;**或以下c
、s
或[
转换说明符应用于类型指针指向wchar_t
的参数。这修改了该节的
/12
段落,该段落指出,对于%f
:匹配可选带符号浮点数、无穷大或
NaN
,其格式与strtod
函数主题序列的预期格式相同。相应的参数应该是一个指向浮点数的指针。qltillow2#
对于
scanf
,%f
读入float
,%lf
读入double
。对于
printf
:在C99和更高版本中,它们都是相同的,它们打印float
或double
。在C89中,%lf
导致了未定义的行为,尽管将其视为%f
是一个常见的扩展。在
printf
中,一个说明符可以用于两个不同的类型的原因是因为 default参数promotions;float
类型的参数在用于调用函数且不匹配函数原型中的参数时提升为double
。所以printf
在任何情况下都只能看到double
。9udxz4iz3#
对于使用printf函数族的输出,%f和%lf说明符的含义相同;忽略L。两者都需要一个对应的double类型的参数,但是float类型的参数会升级为double,这就是为什么float类型没有单独的说明符。(此提升仅适用于printf等变元函数,以及没有原型声明的函数,而不适用于一般的函数调用。)对于类型long double,正确的格式说明符是%Lf。
对于使用scanf函数族的输入,浮点格式说明符为%f、%lf和%Lf。它们分别需要指向float、double和long double类型的对象的指针。(没有float-to-double提升,因为参数是指针。一个float值可以提升为double,但是一个float* 指针不能提升为double*,因为指针必须指向一个实际的float对象。
但是在使用scanf函数时要小心,要使用数字输入。没有定义溢出检查,如果输入超出了类型的范围,则程序的行为未定义。为了安全起见,将输入读入字符串,然后使用类似strtod的方法将其转换为数值。(请参阅文档以了解如何检测错误。)
moiiocjp4#
%lf中的宽度修饰符被printf()优雅地忽略。或者,更准确地说,%f需要一个double - varargs将始终将float参数提升为double。