标签:
原文地址:http://blog.sina.com.cn/s/blog_605f5b4f0100x3ep.html
首先声明:在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("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;
}
标签:
原文地址:http://www.cnblogs.com/codecamel/p/4702992.html