printf("%d",5.01)和printf("%f",5)的输出结果
printf("%f\n",);
printf("%d\n",5.01);
printf("%f\n", (float));
printf("%f\n", .f);
输出结果:

看到结果,会感觉非常奇怪。1处怎么会输出0呢?2又为何会显示这么大的一个数呢?
解释:
1,之所以没输出5,这是C语言设计的原因。
2,之所以输出0,这是计算机体系结构的问题。
具体来说:
printf函数不会进行任何类型转换,它只是从内存中读出你所提供的元素的值(按照%d,%f等控制字符提示的格式)。C语言设计中,int类型一般是32bit或者16bit,而float一般是64bit,并且有可能使用科学计数保存。这点就和huhugo88所说一样,5在内存中为00000000,00000101。而且5一般都在静态区,程序的静态存储区默认是0,那么当用%f来读时,就会读64bit,也就是会读之前的很多位0,最后按照(有效数字)×(基数2)pow(指数)的方式来取数,自然结果是0
之所以Vc中不允许这种情况,而有些编译器就允许这么输出就是编译器设置的问题。按理说,这样访问内存是属于越界访问,应该禁止。不过只是读,伤害性不大而已。 对于单精度浮点数(32bit),不少c语言编译系统以24位表示小数部分(包括1bit符号位),以8位表示指数部分。 ==========================printf("%d\n",5.01); 为什么输出一个大数?在讲这个题目之前,预备知识,讲一下,printf函数,输入参数是读入缓冲区保存,再按照%?的格式从缓冲区中读出数据,并据此格式解释数据。
有了这个知识之后,在讲程序员面试宝典上看到一个题:
#include "stdio.h"
int main(int argc, char* argv[])
{
printf("%d\n",5.01);
return ;
}
输出结果为:188978561
然后开始研究为什么会是这个数?
5.01是double类型,内存中占8个字节,保存在缓冲区。而%d为整型,占4个字节,printf从缓冲区中读入4字节,先读到低32位的数据。也就是说printf输出的应该是5.01以double类型保存数剧的低32位。为了检验此结果是否正确,对比5.01在内存中的表示与输出。
#include "stdio.h"
int main(int argc, char* argv[])
{
double d = 5.01;
int *p = (int *)(&d);
int rst = ;
printf("1).%x\n",*p);
printf("2).%x\n",*(p+));
printf("3).%x\n",rst);
return ;
}
输出为:
1).0x70a3d70a
2).0x40140a3d
3).0x70a3d70a
这也就证明了%d输出了5.01的低32低。5.01的double类型,在内存的的表示为0x40140a3d70a3d70a。
事情看似也就完成了。
我又想,如果输入是浮点类型的5.01f,又会发生什么呢?
#include "stdio.h"
int main(int argc, char* argv[])
{
float f = 5.01f;
int *p = (int *)(&f);
printf("1).0x%x\n",*p);
printf("2).0x%x\n",5.01f);
return ;
}
输出:
1).0x40a051ec
2).0x80000000
我们发现,此时输出的并不是浮点类型5.01f的内存的表示,这是为什么呢?
然后看到一个说法,是printf会把%f按double类型输出,也就是说会把参数float型的转成double型再输出。
但现在并不是%f,当然用%f显示的是正确的结果。于是我猜测,printf是将所在float型读入的数据都自动的转化为double型了,然后%f就按double处理,而我们这是%d,所以显示的为float转化为double型后的低4字节。
验证此想法:
#include "stdio.h"
int main(int argc, char* argv[])
{
double f = 5.01;
int *p = (int *)(&f);
printf("1).0x%x\n",*p);
printf("2).0x%x\n",*(p+));
printf("3).0x%x\n",5.01f);
return ;
}
输出:
1).0x70a3d70a
2).0x40140a3d
3).0x80000000
但是我们发现结果并不一样,于是我又猜想,也是许printf将float转化为double的方式与默认的方式不一样
5.01d的默认的表示为:0x40140a3d70a3d70a,在上面已经说明了
#include "stdio.h"
int main(int argc, char* argv[])
{
printf("0x%8x\n0x%8x\n",5.01f);
return ;
}
输出为:
0x80000000
0x40140a3d
与是发现printf将5.01f->5.01d的表示是:0x40140a3d80000000
接着就是看这两个值是否都是为5.01了:
#include "stdio.h"
int main(int argc, char* argv[])
{
int d1[], d2[];
d1[]=0x80000000;
d1[]=0x40140a3d;
d2[]=0x70a3d70a;
d2[]=0x40140a3d;
double *p1 = (double *)d1;
double *p2 = (double *)d2;
printf("1).%f\n",*p1);
printf("2).%f\n",*p2);
return ;
}
输出为:
1).5.010000
2).5.010000
也就证明了0x40140a3d80000000,与0x40140a3d70a3d70a都是5.01d在机器中的表示。前者为5.01f(0x40a051ec)由printf转化为double后的表示,后者为5.01d的默认的表示。
总结:printf将输入的浮点型参数全都自动转化为双精度型,且与默认的双精度的表示方法是不同的。最重要一点,printf不安全,类型不安全,要是类型不对了,也许我们就挂了
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/fengyunjh/archive/2011/03/07/6230164.aspx
=======================================================================================================================
通过以上解释,我们大致明白:
1. printf输出float型时,会自动转化成double型;
2. 由于存储时,都是先低位,再高位,同时经过转化成double,前面会取很多0(越界访问);
3. 5.01,打印时按照int来取,只取前四个字节。
printf("%d",5.01)和printf("%f",5)的输出结果的更多相关文章
- 与C中printf并列的System.out.printf 用法(转载)
转载地址: https://blog.csdn.net/qq_39017218/article/details/80042287 printf的格式控制的完整格式: % - 0 m.n l或h ...
- printf("%*s\n", 1, ""); 使用"printf();" 的格式化输出动态制定等宽度输出。
#include <stdio.h> #include <string.h> int main() { const char the_text[] = "this i ...
- poj-1015(状态转移的方向(01背包)和结果的输出)
#include <iostream> #include <algorithm> #include <cstring> #include <vector> ...
- printf("%f\n", 3);输出结果为什么是0.000000(转载)
printf不会关心你输入的参数的类型,你输入的实际是 printf("%f",3),但是这个整型3不会被隐式类型转换为浮点型,而是被直接按内存内容当作浮点型 也就是说,内部使用等 ...
- C语言的常用printf打印占位符%d, %u, %f, %s, %c, %o, %x
占位符含义及用法 代码: #include <stdio.h> int main(int argc, char const *argv[]) { , b = -; // 默认10进制赋值 ...
- VC2010 MFC中实现printf调试功能,即MFC程序利用控制台输出调试信息。
1.在项目自动生成的stdafx.h文件中添加下面头文件 #include <io.h> #include <fcntl.h> #include <stdio.h> ...
- printf 参数检查 __attribute__((format(printf, 1, 2)))
With GCC, I can specify __attribute__((format(printf, 1, 2))) , telling the compiler that this funct ...
- Educational DP Contest F - LCS (LCS输出路径)
题意:有两个字符串,求他们的最长公共子序列并输出. 题解:首先跑个LCS记录一下dp数组,然后根据dp数组来反着还原路径,只有当两个位置的字符相同时才输出. 代码: char s[N],t[N]; i ...
- 算法进阶面试题01——KMP算法详解、输出含两次原子串的最短串、判断T1是否包含T2子树、Manacher算法详解、使字符串成为最短回文串
1.KMP算法详解与应用 子序列:可以连续可以不连续. 子数组/串:要连续 暴力方法:逐个位置比对. KMP:让前面的,指导后面. 概念建设: d的最长前缀与最长后缀的匹配长度为3.(前缀不能到最后一 ...
随机推荐
- vue之指令系统
所谓指令系统,大家可以联想咱们的cmd命令行工具,只要我输入一条正确的指令,系统就开始干活了. 在vue中,指令系统,设置一些命令之后,来操作我们的数据属性,并展示到我们的DOM上. OK,接下来我们 ...
- SharePoint 2013 字段属性之JSLink
在SharePoint 2013中,SPField新增加了一个属性是JSLink,使用客户端脚本修改字段前台展示,我们可以用很多方法修改这个脚本的引用,然后来修改脚本,下面,我们举一个简单的例子. 具 ...
- iOS 截屏分享(包含状态栏与不包含状态栏)
iOS8以上的新方法PhotoKit 监听截图相册变化,取最后一张图片:http://www.hangge.com/blog/cache/detail_1515.html PhotoKit 获取本机相 ...
- Nginx限制IP访问及获取客户端realip实战
做网站时经常会用到remote_addr和x_forwarded_for这两个头信息来获取客户端的IP,然而当有反向代理或者CDN的情况下,这两个值就不够准确了,需要调整一些配置.Nginx作为web ...
- hdu3038 How many answers are wrong【并查集】
TT and FF are ... friends. Uh... very very good friends -________-b FF is a bad boy, he is always w ...
- Java编程思想第四版随书源码官方下载方法
见不少人在找net.mindview.util.Print,CSDN上有下载,收积分,以下是官网的下载方法,免费: 官网链接:http://mindview.net/ 电子书下载地址:http://w ...
- CodeForces - 950C Zebras 模拟变脑洞的天秀代码
题意:给你一个01串,问其是否能拆成若干形如0101010的子串,若能,输出所有子串的0,1 的位置. 题解:一开是暴力,然后瞎找规律, 最后找到一种神奇的线性构造法:扫一遍字符串,若为0就一直竖着往 ...
- Git:上传GitHub项目操作步骤
git教程:git详解.gitbook #首次上传步骤 首先在工程文件位置处右键git bash here 本地创建ssh key $ ssh-keygen -t rsa -C "your_ ...
- 从url到请求 再到页面生成
百度面试 从url到请求 再到页面生成 - MartinDing - 博客园 https://www.cnblogs.com/martinding/p/7458723.html
- C# 枚举 小总结
枚举 枚举类型声明为一组相关的符号常数定义了一个类型名称. 枚举类型为定义一组可以赋给变量的命名整数常量提供了一种有效的方法.例如:假设你必须定义一个变量,该变量的值表示一周中的一天.该变量只能存储七 ...