欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

关于浮点型数据在printf函数中的输出方式

程序员文章站 2024-03-18 17:54:04
...
前段时间在学习C语言的时候遇到了一些当时无法解释的奇怪问题,这里说一下具体的解决过程。
大家先看一下这段代码:
    int main()
    {
        float num = 1.000000;
        printf("%#x----%d",num,num);
        printf("%d----%#x",num,num);
        return 0;
    }
我在编译后发现了一个奇怪的现象,编译结果如图:
![输出结果](https://img-blog.csdn.net/20180728125907250?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyMjk2OTg1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
这个问题,一开始我只是奇怪为什么前面格式控制符输出的总是0,为此我专门用sizeof(float),求得了float占空间4个字节,但是为什么会输出这么奇怪的结果?于是我在网上查了一下,嘿嘿!还真发现了一道相似的题目:(感谢牛客网提供的题目!)
链接:https://www.nowcoder.com/questionTerminal/316082aaacfe4c3f8faf004e3e0fcf6d

来源:牛客网
int main(){
int a;float b,c;
scanf(“%2d%3f%4f”,&a,&b,&c);
printf(“\na=%d,b=%d,c=%f\n”,a,b,c);
}
若运行时从键盘上输入9876543210l,则上面程序在gcc编译器下的输出结果是
A a=98,b=765,c=4321.000000
B a=98,b=0,c=0.000000
C a=98,b=765.000000,c=4321.000000
D a=98,b=765.0,c=4321.

结果为B,具体分析过程我就不说了,有兴趣的小伙伴可以自己去看一下,牛客网的大佬分析的非常详细!而大佬在分析的时候,我注意到了两点:
1、printf函数在打印输出的过程有一个入栈和出栈的过程,这导致了一些比较经典的题型:
例如: 
        int i = 10;
        printf ( "%d---%d---%d\n",i,i++,i++ ) ;
2、第二点就是我真正想讲的了,float类型的变量在printf函数中是自动转换成了double类型的变量的,这样的话,float变量就不再是4个字节,而是8个字节了,所以这就解释一开始我写的代码中为什么无论我的输出格式控制符是%d还是%#x,结果前面一个都是0了。
很明显,%#x和%d都是整型数据的输出格式控制符,整型输出4个字节,所以我看似输出了两次,实际情况却是:我只是把一个占8个字节的浮点型数据分两次输出了,而第二个浮点型数据就这样被遗忘了(我觉得是被遗忘了。。。)
另外,这里需要注意一点,由于printf函数中是将float类型数据转换成了double类型数据,所以float类型数据的存储类型也发生了变化,变成了double类型的存储方式,千万不要以为简单的加上4个0字节就行了,否则你会发现,你会看不懂后面为什么是0x3ff00000这个数据了(去参考一下double类型数据的存储方式,你就明白了),0x3ff00000转换成二进制如下图:
0011 1111 1111 0000 0000 0000 0000 0000
最高位是符号位,0表示正数,然后3ff转换成十进制刚好是1023,根据IEEE规则,double类型数据的指数的值为了表示负数,需要减去1023,这么一减,明显是0,2^0 * 1.0000...(这儿的1不占内存,注意区分),结果刚好是1.00000,如果你用float类型的存储方式去算的话...呵呵,我没试过,有兴趣可以自己去试试。
但是随着我仔细一想,发现还是有问题(笑容在脸上逐渐凝固。。。)按照入栈和出栈的道理,为什么我输出的两个数据,会是前面一个为0,double的最高位为什么到低4个字节去了,很是忧伤。。。感觉应该后面一个数为0,这个问题我连怎么在网上找都没有头绪,只能厚着脸皮去咨询了一下前辈们(机智如我...),大佬听了一下我的问题,说了一句话:“去网上看看小端序是什么,你就明白了”,我又去百度了一下“小端”的概念,一下就明白了为什么了:
所谓“小端”,是一种电脑的存储方式,(目前大多数电脑都是小端序电脑),举个通俗的例子来说,一个整型数据0x12345678,在电脑中存储方式是怎么样的呢?整型数据占4个字节,即2位16进制数据占1个字节,如果你的电脑是小端序,那么存储方式就是 :
78  56  34  12 
一开始或许有点难以理解,慢慢就会明白了,当然如果是倒过来的话,那就是大端序了,不过这种电脑我还没见过的...说回来,我们现在要首先明白,printf中的float数据是“不存在”的,浮点型数据全是double类型,占8个字节,这样的话,假设这个double类型的数据的值是:0x0123456789abcdef,16个十六进制数,按照小端序,存储方式为:
ef  cd  ab  89  67   45  23  01
注意首地址在最前面的"ef"这儿哦,由于输出%d是输出4个字节,因此输出0x89abcdef,继续输出的话才是最高位0x01234567.
好了,这道题的问题到这里就完全没有问题了,希望大家可以学到一些知识!!