• 【转】printf格式串中的%f的输出格式和内容


    原文地址: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 ", 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 ", 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 ", 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 ", 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 ",a);
        printf("b:%d ",b);
        printf("c:%d ",c);
    结果:
    a:10
    b:20
    c:5
    分析:输出格式和值的格式对应,没有问题

        printf("a:%f ",a);
        printf("b:%f ",b);
        printf("c:%f ",c);
    结果:
    a:0.000000
    b:0.000000
    c:0.000000
    分析:输出格式和值的格式不对应,所有int的%f输出结果都为0;由后面的分析可知,这是由于%f和int类型不匹配,%f故输出0

        printf("a:%f,b:%d ",a,b);
        printf("a:%f,b:%d,other:%d ",a,b);
        printf("a:%f,b:%d ",a,b,c);
        printf("a:%f,b:%d,c:%f ",a,b,c);
        printf("a:%f,b:%d,c:%d ",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 ",a,b);和结果a:0.000000,b:10可以看出编译器的顺序是这样的:
     编译器顺序执行。首先执行%f,没有对应的类型,结果为0.000000。执行%d,对应的第一个int类型为a=10,结果为10。
     同上,printf("a:%f,b:%d,other:%d ",a,b)执行时,输出第二个%d时,对应第二个int类型b=20。
     同上,printf("a:%f,b:%d ",a,b,c)执行时,%d执行对于a=10,b和c都没有用到
     同上,printf("a:%f,b:%d,c:%f ",a,b,c)执行时,%d执行对于a=10,之后的%f没有对应类型,b和c都没有用到;
     同上,printf("a:%f,b:%d,c:%d ",a,b,c)执行时,%f无对应,输出0,%d%d分别对应于a和b;

       

        float x=10.0f;
        int y=5
    ;
       
        printf("x:%d ",x);
        printf("y:%d ",y);
    结果:
    x:4196537
    y:5
    分析:printf("x:%d ",x)输出x:4196537可以看到如果值的字节数>要输出的字节数,截取值字节的一部分输出.

        printf("x:%f ",x);
        printf("y:%f ",y);
    结果:
    x:10.000000
    y:10.000000
    分析: printf("y:%f ",y);输出y是10f是令我惊讶的事情。因为在一开始已经定义了c=5,而printf("c:%f ",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 ",c)是c之后的8字节的值为0f

        printf("x:%d,y:%d ",x,y);
        printf("x:%d,y:%f ",x,y);
        printf("x:%f,y:%d ",x,y);
        printf("x:%f,y:%f ",x,y);
        printf("x1:%d,x2:%d,y:%d ",x,y);
        printf("x1:%f,x2:%d,y:%d ",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 ",x,y)中printf按照顺序执行,x与%d不匹配,找下一个参数值y,一和%d匹配,故输出5,而之后的%d,由于没有了参数值,寻找y的下一个4字节并作为int输出476096928


    printf("x:%d,y:%f ",x,y)这里printf按照顺序执行,x与%d不匹配,找下一个参数值y,和%d匹配,故输出5,而之后的%f,则读取后面的8个字节输出,可以看到%f 输出为10f,同%f单独输出y相同。

    printf("x:%f,y:%d ",x,y)类型匹配,正常输出


    printf("x:%f,y:%f ",x,y)%f和x匹配,输出10f,而%f和y不匹配,读取y之后的8个字节输出,但这次居然为0f?又开始怀疑y输出10f的地址就是x的地址?怀疑所有%f的int为0了??


    printf("x1:%d,x2:%d,y:%d ",x,y);和%d匹配的是y=5,之后%d和%d都是读取y之后的4个字节然后输出476096928和476092288
    printf("x1:%f,x2:%d,y:%d ",x,y);x和y匹配之后,%d只好读取y之后的一个4字节输出476096928

    可以看到%d输出y之后的4字节时,(1)第一次是476096928,(5)第二次是476096928和476092288(6)第三次为476096928


        return 0;
    }

  • 相关阅读:
    LRU算法实现 最近最久未使用
    快速排序
    redis 常用命令
    实例:接口并发限流RateLimiter
    Hadoop伪分布式安装
    ssl免密登录(centos6)
    Linux下安装jdk-7u67-linux-x64.rpm
    Mosquitto安装和使用
    MQTT linux centOS7 部署
    CentOS更换yum源
  • 原文地址:https://www.cnblogs.com/codecamel/p/4702992.html
Copyright © 2020-2023  润新知