【转】printf格式串中的%f的输出格式和内容
⾸先声明:在VC++下编译printf不会⾃动做类型转换,⽐如int a=3; printf("%f",a);运⾏过程中会报错,runtime error R6002: floating point not loaded。如下均是在linux的程序。
如下是借鉴别⼈的,有助于分析原因。
以⼩数格式输出⼀个整数:
int a = 0, b = 0;
printf("%f, %d", a, b);
可是运⾏结果并不尽如⼈意,%f字段输出了0,%d字段输出⼀个较⼤的数据。
因为我最近刚阅读了浮点数的内存表⽰⽅法,所以对上述代码做出解释如下:
%f为double类型,需要两个字节(转载修正:double型数据类型占8个字节,int为4个字节,故需要两个int类型)表⽰,所以,printf在遇到%f时即将a,b的两个整型数据都读了去,⽽到了需要输出%d的时候,只能读取b的下⼀个单元,⾃然不是所期望的数据了。
⾃⼰的评论:
这个⾥⾯的printf是按照顺序的⽅式执⾏的,先%f,读去了8个字节,值的队列⾥⾯没有了元素,%d就去读下⼀个字节了。
但是有朋友说%f是float类型,%lf才是double类型,具此我特意查阅了MSDN和Linux man⼿册,均没有发现此类描述,在linux man⼿册中,说明%lf为long double类型。
⾃⼰的评论:
lf和f貌似没有什么区别。
为了说明问题,我⼜做了⼏个实验:
实验⼀,检查%f需要读取⼏个字节
int a=0, b=0, c=5;
printf("%f,%d\n", a, b, c);
输出结果:
0,5
结论:%f读取8个字节,即两个整型⼤⼩
⾃⼰的评论:
个⼈认为⽂章的作者执⾏这段代码换了编译器,这个printf是按照栈的⽅式逆序执⾏的,先读%d,弹出c=5,后读%f,弹出b和a。
实验⼆,检查%lf需要读取⼏个字节
int a=0, b=0, c=5;
printf("%lf,%d\n", a, b, c);
输出结果:
0,5
结论:%lf也读取8个字节(也许和机器位宽有关,我是32位的机器)
⾃⼰的评论:
同上。这个printf是按照栈的⽅式逆序执⾏的,先读%d,弹出c=5,后读%lf,弹出b和a。
实验三,检查printf读取float类型数据
float a=0.0f;
int b=5;
printf("%f,%d\n", a, b);
输出结果:
0.0,5
结论:float类型只占4个字节的数据,但前⾯实验⼀已经证明%f会读8个字节,即double类型的宽度,所以,编译器在将float类型参数⼊栈的时候,事先转换成了double类型。
⾃⼰的评论:
同上。这个printf是按照栈的⽅式逆序执⾏的,先读%d,弹出b=5,后读%f,弹出a和后⾯的4个字节,⾄于为何是0.0 后⾯有说明。
实验四,再次证明实验三的结论
float a=0.0f;
int b=5;
printf("%d,%d,%d\n", a, b);
输出结果:
0,0,5
结论:a在⼊栈的时候,占了8个字节。
⾃⼰的评论:
同上。这个printf是按照栈的⽅式逆序执⾏的,先读%d,弹出b=5,再读%d,弹出a的⼀部分4个字节,后读%d,弹出a后⾯的4个字节,⾄于为何是0.0 后⾯有说明。
⾃⼰的实验:
由于使⽤的编译器不同,得出结果也不同,如下是⾃⼰的实验和结果分析,linux下g++。由于使⽤的编译器采⽤了不同的printf的输出,上述是逆序,我的是正序。
#include<stdio.h>
#include<stdlib.h>
int main()
{
int a=10,b=20,c=5;
printf("a:%d\n",a);
printf("b:%d\n",b);
printf("c:%d\n",c);
结果:
a:10
b:20
c:5
分析:输出格式和值的格式对应,没有问题
printf("a:%f\n",a);
printf("b:%f\n",b);
printf("c:%f\n",c);
结果:
a:0.000000
b:0.000000
c:0.000000
分析:输出格式和值的格式不对应,所有int的%f输出结果都为0;由后⾯的分析可知,这是由于%f和int类型不匹配,%f故输出0
printf("a:%f,b:%d\n",a,b);
printf("a:%f,b:%d,other:%d\n",a,b);
printf("a:%f,b:%d\n",a,b,c);
printf("a:%f,b:%d,c:%f\n",a,b,c);
printf("a:%f,b:%d,c:%d\n",a,b,c);
结果:
a:0.000000,b:10
a:0.000000,b:10,other:20
a:0.000000,b:10
a:0.000000,b:10,c:0.000000
a:0.000000,b:10,c:20
分析:printf("a:%f,b:%d\n",a,b);和结果a:0.000000,b:10可以看出编译器的顺序是这样的:
编译器顺序执⾏。⾸先执⾏%f,没有对应的类型,结果为0.000000。执⾏%d,对应的第⼀个int类型为a=10,结果为10。
同上,printf("a:%f,b:%d,other:%d\n",a,b)执⾏时,输出第⼆个%d时,对应第⼆个int类型b=20。
同上,printf("a:%f,b:%d\n",a,b,c)执⾏时,%d执⾏对于a=10,b和c都没有⽤到
同上,printf("a:%f,b:%d,c:%f\n",a,b,c)执⾏时,%d执⾏对于a=10,之后的%f没有对应类型,b和c都没有⽤到;
同上,printf("a:%f,b:%d,c:%d\n",a,b,c)执⾏时,%f⽆对应,输出0,%d%d分别对应于a和b;
float x=10.0f;
int y=5;
printf("x:%d\n",x);
printf("y:%d\n",y);
结果:
x:4196537
y:5
分析:printf("x:%d\n",x)输出x:4196537可以看到如果值的字节数>要输出的字节数,截取值字节的⼀部分输出.
printf("x:%f\n",x);
printf("y:%f\n",y);
结果:
x:10.000000
y:10.000000
分析: printf("y:%f\n",y);输出y是10f是令我惊讶的事情。因为在⼀开始已经定义了c=5,⽽printf("c:%f\n",c)的结果为0,y的值也为5。
从c来看如果int按%f输出由于类型不匹配,规定%f输出0;
⽽从y看如果int按%f输出,貌似是将y和y之前或者y之后的四个字节,⼀并作为⼀个float或者double类型进⾏%f输出。
或者从c来看如果int按%f输出也是按照8个字节,但是很不巧,所有a、b、c按照8字节输出都为0?
事实是:
两者的结合,%f和y类型不匹配,%f从y之后读取8个字节进⾏输出,这8个字节的float值恰好是10f(从下⾯的结论得知)
⽽printf("c:%f\n",c)是c之后的8字节的值为0f
printf("x:%d,y:%d\n",x,y);
printf("x:%d,y:%f\n",x,y);
printf("x:%f,y:%d\n",x,y);
printf("x:%f,y:%f\n",x,y);
printf("x1:%d,x2:%d,y:%d\n",x,y);
printf("x1:%f,x2:%d,y:%d\n",x,y);
结果:
x:5,y:476096928
x:5,y:10.000000
x:10.000000,y:5
x:10.000000,y:0.000000
x1:5,x2:476096928,y:476092288
x1:10.000000,x2:5,y:476096928
分析:
printf怎么格式化输出printf("x:%d,y:%d\n",x,y)中printf按照顺序执⾏,x与%d不匹配,下⼀个参数值y,⼀和%d匹配,故输出5,⽽之后的%d,由于没有了参数值,寻y的下⼀个4字节并作为int输出476096928
printf("x:%d,y:%f\n",x,y)这⾥printf按照顺序执⾏,x与%d不匹配,下⼀个参数值y,和%d匹配,故输出5,⽽之后的%f,则读取后⾯的8个字节输出,可以看到%f 输出为10f,同%f单独输出y相同。
printf("x:%f,y:%d\n",x,y)类型匹配,正常输出
printf("x:%f,y:%f\n",x,y)%f和x匹配,输出10f,⽽%f和y不匹配,读取y之后的8个字节输出,但这次居然为0f?⼜开始怀疑y输出10f的地址就是x的地址?怀疑所有%f的int为0了??
printf("x1:%d,x2:%d,y:%d\n",x,y);和%d匹配的是y=5,之后%d和%d都是读取y之后的4个字节然后输出476096928和476092288
printf("x1:%f,x2:%d,y:%d\n",x,y);x和y匹配之后,%d只好读取y之后的⼀个4字节输出476096928
可以看到%d输出y之后的4字节时,(1)第⼀次是476096928,(5)第⼆次是476096928和476092288(6)第三次为476096928
return 0;
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论