此问题已在此处有答案:
What is the difference between %f and %lf in C?(4个答案)
12小时前关闭。
在www.example.com上的一篇文章中w3resource.com,我看到了以下代码:
double x, y;
pr1 = sqrt(pr1);
x = (-b + pr1)/(2*a);
y = (-b - pr1)/(2*a);
printf("Root1 = %.5lf\n", x);
printf("Root1 = %.5lf\n", y);
文章说取三个浮点数。但是在他们的解决方案(这个代码片段)中,他们使用了%lf
说明符。为什么使用%lf
而不是%f
?我也可以使用%f
而不是%lf
来处理浮点数吗?
如果我使用float
关键字而不是double
,并使用%f
,是否有任何问题?输出对我来说是一样的。
2条答案
按热度按时间li9yvcax1#
%f
在printf
和scanf
系列函数中有不同的含义:printf
中,%f
和%lf
是等价的,并且两者都由double
匹配。这是因为在可变参数函数中,当调用函数时,所有float
参数都提升为double
,因此在语言级别传递float
和double
没有区别。scanf
中,%f
匹配float*
,%lf
匹配double*
,这种区别非常重要。使用错误类型的指针将导致未定义的行为。您还可以使用cdecl+来更好地理解
printf
和scanf
调用。输出如下:当有疑问时,使用
%f
表示float
,使用%lf
表示double
,即使在printf
中,两者之间也没有区别。否则,您将在scanf
和printf
字符串之间引入无意义的不一致。* 浮点数 * 注意事项
您可能对
float
和 floating-point number 的含义感到困惑。float
、double
、long double
等是C中的浮点数。当文章中提到 * 浮点数 * 时,它们也可能意味着double
,_Decimal32
,_Float128
等。为什么
scanf
不像printf
一样将float*
升级为double*
?这是不可能的,因为我们存储
float
的对象不能用于存储double
。double
在一个float
,其中包括四个字节,这是不可能的。qkf9rpyu2#
来自C标准(7.21.6.1 fprintf函数)
l(ell)指定后面的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转换说明符没有影响。
和(6.5.2.2函数调用)
7如果表示被调用函数的表达式有一个包含原型的类型,则参数被隐式转换为相应参数的类型,就像通过赋值一样,每个参数的类型都是其声明类型的非限定版本。函数原型声明符中的省略号表示法会导致参数类型转换在最后一个声明的参数之后停止。默认参数升级是对尾随参数执行的。
和/或
6如果表示被调用函数的表达式的类型不包括原型,则对每个参数执行整数提升,并且具有float类型的参数被提升为double。这些称为默认参数提升。
使用长度修饰符
l
和转换说明符f
只会让代码的读者感到困惑。它的使用会产生问题。代码的读者会认为代码的作者不知道长度修饰符没有效果,或者如果没有长度修饰符,printf
(或fprintf
)的调用确实会有未定义的行为,并且使用长度修饰符是必要的。至于使用长度修饰符调用
scanf
,则函数处理float *
或double *
类型的指针。也就是说,default参数promotions 不会应用于它们。所以要区分一个指针是指向float
类型的对象还是指向double
类型的对象,你必须使用长度修饰符l
和转换说明符f
以及double *
类型的指针,或者不使用长度修饰符float *
类型的指针。在调用
printf
(或fprintf
)时,对double
类型的对象使用长度修饰符l
只会使代码更难维护,因为例如,如果输出变量的类型将从double
类型更改为float
类型,则必须找到并更改使用该变量的所有printf调用。