首页 > 代码库 > c语言的printf输出浮点数的一些问题

c语言的printf输出浮点数的一些问题


在printf时:如果以%f格式输出,将输出8个字节(scanf输入时,%f是4个字节)

                   在参数入栈时如果是float型或者double型 直接入栈8个字节,此时输出及后续输出都没问题

                    但如果参数小于8个字节且不是float型:比如int   shor int  ,就会扩展符号位,成为4个字节再入栈,但是输出的是8个字节,所以会读取其他参数的入栈结果

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, const char *argv[])
{
    int a = 3;
    int b = 5;
    printf("%f %d\n", a, b);
    return 0;
}

在linux下的gcc输出结果是:  0.000000    134513801      -->后面这个值是一个无用值,比如int x;  printf("%d\n", x)  -->输出的就是:134513801

在vs2013下的输出结果是:0.000000   0     vs中对int x; printf("%d\n",x)会出现错误,因为x未初始化,

-->上述入栈结果是(十六进制):

栈顶                                 栈底

     03 00 00 00    05 00 00 00  

-->%f 读取8个字节,直接把b的入栈结果读走了


  符号位  阶码  尾数  总位数
  短浮点数   1    8   23   32
  长浮点数   1    11   52   64

在32位浮点数的读取中:从内存中读出0x 03 00 00 00后,因为是小端模式,所以变成0x 00 00 00 03

 0   000 0000 0  000 0000 0000 0000 0000 0011

第一个0是符号位:表正

第2到9位是阶码,32位浮点数的指数偏移量是127, 所以此处是-127

后面的均为小数点后面的:小数点前为1

-->(1 + 2^(-22) + 2^(-23)) * 2^(-127)

趋近于0;

在64位浮点数中:则阶码偏移量为:2^(10) - 1


例1:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, const char *argv[])
{
    int a = 3;
    int b = 0xffffffff;
    printf("%f %d\n", a, b);
    return 0;
}

在gcc中结果为:-nan    134513801     -->-nan表示负无穷大

在VS2013中结果为:-1.#QNAN0   0

printf的栈中: 03 00 00 00 ff ff ff ff

-->按%f读取的时候:ff ff ff ff 00 00 00 03

-->按浮点数解析相应的位!


例2:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, const char *argv[])
{
    int a = 0x10000003;
    int b = 0x40110000;
    printf("%f %d\n", a, b);
   
    int c[2];
    c[0] = 0x10000003;
    c[1] = 0x40110000;
     double d = *(double*)c;
     printf("%f\n", d);
    return 0;
}

gcc中:


分析:

在第一个printf的栈中:  03 00 00 10 00 00 11 40

-->以%f读出时出栈结果:0x 40 11 00 00 10 00 00 03

-->64位浮点数解析:0100 0000 0001 0001 0000 0000 0000 0000 0001 0000 0000 0000 0000 0000 0000 0011

符号位:0

阶码:100 0000 0001    -->11位  -->减去偏移量:2^(10) -1  -->结果为2

小数位:0001 0000 0000 0000 0000 00....

最后大小:(1 + 2^(-4) + 2^(-52) + 2^(-51) + 2^(-24)) * 2^(2)

 -->2进制:100 + 2^(-2)   -->4.250000 


例3:
反过来看
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, const char *argv[])
{
    int a = 5;
    float b = 3.0;
    printf("%d %d\n" , a, b);
    return 0;
}

输出结果: 5   0

b虽然是4个字节的float型,但是在入栈时会变换为8个字节的fdouble型
--->float型的3.0的表示:0x 40 40 00 00
                       -->内存中: 00 00 40 40
                      -->printf输出时入栈变为扩展8个字节的double型: 00 00 00 00 00 00 08 40
-->此时printf的栈中:
                        05 00 00 00  00 00 00 00 00 00 08 40
-->以%d格式输出两次: 5   0
32位的float型的3二进制码:   0 100 0000 0 100  0000 0000 0000 0000 0000
64位的double型3的二进制:   0 100 0000 0000  1000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
对比:                   32                    64
符号位                    0                     0
阶码:                100 0000 0       100 0000 0000    -->64位在32位后面添加了3个0
尾数 :               100.....               100....                   -->64位在32位后面添加了29个0

总结:
 printf 以%f格式输出时输出8个字节,float类型输出时入printf的栈要扩展为double型的8个字节!
printf的返回值为实际控制输出的字符数(不包括字符串末尾的‘\0‘),


c语言的printf输出浮点数的一些问题