printf 输出浮点数
在测试printf
函数输出结果时,写了如下代码:
/**
* printf:格式化输出函数
* printf函数不会按照格式控制而对数据类型进行转换,不管三七二十一,
* 抓到二进制数据就按照格式控制符对数据进行解析。
*/
#include <stdio.h>
int main(void)
{
//test_1
float a = 10.9;
printf("%d\n", a);
//以十进制形式输出带符号整数(正数不输出符号)
//输出 -1073741824
//(printf 不会将浮点型变量 a 数据类型转换为整型,而是将按照浮点型格式存储的数据直接按照整型数据的格式进行解析打印)
//test_2
int b = 10;
printf("%f\n", b);
//以小数形式输出单、双精度浮点型
//输出 0.000000
//test_3(数据类型转换)
int num_i = 10;
float num_f = (float)num_i;
printf("%f\n", num_f);
//输出 10.000000
//直接对变量进行类型强制转换时:
//编译器先将内存中 num_i 的值当做整型数来处理,然后再按照浮点数的格式将其存储在内存中,最后 printf 以 %f (实数)格式打印出来
//test_4(与 test_1、test_2、test_3 进行对比)
int* fa = (int*)&a;
float* fb = (float*)&b;
printf("%d\n", *fa); //输出结果 1093559910
printf("%d\n", *fb); //输出结果 0
getchar();
return 0;
}
本来以为test_4
的结果会和test_1
和test_2
结果相同,然而结果输出如下:
编译环境为 Dev_C++ 5.11,编译日志如下:
主要观察a
和*fa
输出结果:在 test_4 中,取变量 a 的地址,然后将其地址强制转换成整型数地址,再取其地址中的内容 printf 按照%d
格式输出。在这个过程中并没有改变地址内保存的内容,test_1 和 test_4 都是将其地址中保存的内容按照整型数据进行解析并打印输出,为什么结果会不一样呢??
主要参考了下面的几个帖子:
其中的重点是:printf 格式化输出,在传递参数时,若实参为 float 型数据,编译时会自动转换为 double 类型。我又写了一些代码用来测试,并总结这个问题,具体过程如下:
1.实型常量默认为 double 型
#include <stdio.h>
void main()
{
//实型常量默认为 double 型,后面加 f/F 认为是 float 型
printf("%d\n", sizeof(10.9)); //输出结果 8
printf("%d\n", sizeof(10.9f)); //输出结果 4
}
2.打印如下数据
#include <stdio.h>
int main(void)
{
float a = 10.9;
float b = 10.9f;
double c = 10.9;
double d = 10.9f;
printf("%d\n", a); //输出结果 -1073741824
printf("%d\n", b); //输出结果 -1073741824
printf("%d\n", c); //输出结果 -858993459
printf("%d\n", d); //输出结果 -1073741824
printf("%d\n", 10.9); //输出结果 -858993459
printf("%d\n", 10.9f); //输出结果 -1073741824
printf("%d\n", (double)10.9f); //输出结果 -1073741824
//对比 test_4
int* fa = (int*)&a;
printf("%d\n", *fa); //输出结果 1093559910
return 0;
}
3.对比输出结果--总结
printf("%d\n", a); //输出结果 -1073741824
printf("%d\n", b); //输出结果 -1073741824
printf("%d\n", d); //输出结果 -1073741824
printf("%d\n", 10.9f); //输出结果 -1073741824
printf("%d\n", (double)10.9f); //输出结果 -1073741824
这里输出的都是-1073741824
,只看前四行,对于 printf 传递的实参都是 float 型(由于 printf 格式化输出,在传递参数时,若实参为 float 型数据,编译时都会自动转换为 double 类型数据),所以实际输出结果均等价于第五行,先将 float 型的数据,自动转换为 double 类型,再将 8 字节的 double 类型数据按照%d
格式解析输出。
printf("%d\n", c); //输出结果 -858993459
printf("%d\n", 10.9); //输出结果 -858993459
这里输出的都是-858993459
,对于 printf 传递的实参都是 double 型,所以直接将 8 字节的 double 类型数据按照%d
格式解析输出。那么这里的输出结果和上面的输出结果为什么不同??由于 float 类型和 double 类型直接转换会涉及到精度问题(看下面的代码),所以上面 float 类型的 10.9 转换为 double 类型的数据和 double 类型的 10.9 在计算机中是不同的,所以按照整型数来对数据(01011···)解析,输出的结果是不同的。
#include <stdio.h>
int main()
{
printf("%.15f\n", 3.14f);
printf("%.15f\n", (double)3.14f);
printf("%.15f\n", 3.14);
return 0;
}
其输出的结果如下:
int* fa = (int*)&a;
printf("%d\n", *fa); //输出结果 1093559910
这里输出的结果是1093559910
,和上面的两种结果都不相同,是因为将 float 类型的变量 a 的地址强制转换成整型数地址后,*fa
将被看成是整型数(地址中保存的内容实际并没有改变),所以将*fa
传递给 printf 函数,这里printf("%d\n", *fa);
只是将变量 a 地址中 4 个字节的数据内容按照%d
的格式进行解析并输出打印出来,因此,输出结果与上面两种结果都不同。
后记:换编译器
后来我换了VS 2015
对程序进行编译,会直接给出警告,通过看VS 2015
编译器给出的警告或许就可以直接发现问题了。对于上面 2.打印如下数据 中的程序,VS 2015
的编译信息如下(结合行号看警告信息,注意第18行没有警告):
本来的程序只是为了测试 printf 函数的输出结果,用来验证“ printf 函数不会按照格式控制符而对数据类型进行强制转换。对于 printf,不管三七二十一,只是抓到二进制数据就按照格式控制符对数据进行解析。”但是细心观察,深入思考,就会发现新大陆:)
补充(两天后)
可以打印出变量 a、b、c、d 的地址,然后用调试工具查看数据在计算机内部的存储,可以对上述的 总结 加以验证,请参考 评论 ,具体代码如下:
#include <stdio.h>
int main(void)
{
float a = 10.9;
float b = 10.9f;
double c = 10.9;
double d = 10.9f;
//打印变量的地址,查看数据在计算机内部的存储
printf("%p\n", &a); // 0x412e6666 float 类型内部存储
printf("%p\n", &b); // 0x412e6666 float 类型内部存储
printf("%p\n", &c); // 0x4025cccccccccccd double类型内部存储
printf("%p\n", &d); // 0x4025ccccc0000000 由float类型转换为double类型,其内部存储
printf("\n****************\n");
//以下的printf输出语句是等价的
printf("%d\n", a); //输出结果 -1073741824
printf("%d\n", b); //输出结果 -1073741824
printf("%d\n", d); //输出结果 -1073741824
printf("%d\n", 10.9f); //输出结果 -1073741824
printf("%d\n", (double)a); //输出结果 -1073741824
printf("%d\n", (double)b); //输出结果 -1073741824
printf("%d\n", (double)10.9f); //输出结果 -1073741824
printf("%d\n", 0x4025ccccc0000000); //输出结果 -1073741824
//printf对数据解析:截取低位四个字节 0xc0000000
//补码:1100 0000 0000 0000 0000 0000 0000 0000
//求原码,符号位不变,其余位取反加 1
//原码:1100 0000 0000 0000 0000 0000 0000 0000
//十进制表示:-1073741824
printf("\n****************\n");
//以下的printf输出语句是等价的
printf("%d\n", c); //输出结果 -858993459
printf("%d\n", 10.9); //输出结果 -858993459
printf("%d\n", 0x4025cccccccccccd); //输出结果 -858993459
//printf对数据解析:截取低位四个字节 0xcccccccd
//补码:1100 1100 1100 1100 1100 1100 1100 1101
//求原码,符号位不变,其余位取反加 1
//原码:1011 0011 0011 0011 0011 0011 0011 0011
//十进制表示:-858993459
printf("\n****************\n");
//对比 test_4
int* fa = (int*)&a;
//以下的printf输出语句是等价的
printf("%d\n", *fa); //输出结果 1093559910
printf("%d\n", 0x412e6666); //输出结果 1093559910
//printf对数据解析:0x412e6666
//补码:0100 0001 0010 1110 0110 0110 0110 0110
//求原码,正数的原码、反码和补码相同
//原码:0100 0001 0010 1110 0110 0110 0110 0110
//十进制表示:1093559910
getchar();
return 0;
}
具体输出结果如下所示:
printf 输出浮点数的更多相关文章
- printf()输出
printf()函数是式样化输出函数, 一般用于向准则输出设备按规定式样输出消息.正在编写步骤时经常会用到此函数.printf()函数的挪用式样为: printf("<式样化字符串&g ...
- [转载] c++ cout 格式化输出浮点数、整数及格方法
C语言里可以用printf(),%f来实现浮点数的格式化输出,用cout呢...? 下面的方法是在网上找到的,如果各位有别的办法谢谢留下... iomanip.h是I/O流控制头文件,就像C里面的格式 ...
- [ZZ]c++ cout 格式化输出浮点数、整数及格式化方法
C语言里可以用printf(),%f来实现浮点数的格式化输出,用cout呢...?下面的方法是在网上找到的,如果各位有别的办法谢谢留下... iomanip.h是I/O流控制头文件,就像C里面的格式化 ...
- //%f表示以十进制格式化输出浮点数 %.2f
//%f表示以十进制格式化输出浮点数 String s1 ="评分: %.1f"; String s2 = String.format(s1, 8.0); System.out.p ...
- printf输出各种类型,cout控制输出各式
; char c = 'A'; int *p = &a; char *st = "ahj"; float x = 3.1415926; cout << & ...
- Win7超级终端查看单片机printf输出
问题描述: 编写单片机C程序时,经常会用到printf输出信息进行查看,如何查看printf输出? 问题解决: (1)编写单片机C程序 ucos是一个实时多任务操作系统,以上是 ...
- C++格式化输出浮点数
主要内容 介绍C++中如何格式化输出浮点数. 控制浮点数输出格式需要包含iomanip头文件. 使用fixed来控制输出的浮点数的小数位是固定的.可参考http://en.cppreference.c ...
- 使用System.out.printf()输出日志重定向到文件后显示混乱问题
写了一个小工具,使用System.out.printf()输出日志,以方便使用者查看,在终端显示没有问题,但重定向到文件就有问题了,会出现一些很奇怪的乱序现象. 上网查询资料,判断应该是跟重定向和Li ...
- 在进行多次scanf时,printf输出错误
随便一处代码,经过改正后,输出正确的 ''' #include <stdio.h> int main(){ int T; scanf("%d",&T ...
随机推荐
- 微信公众号关联小程序AppID是什么
微信公众平台appid在哪 1.appid和appsecret是微信公众平台服务号才有的,如果自己家的公众平台不是服务号,需要升级为服务号. 2.登录服务号,登录“服务”条目,“服务中心”如图. 3. ...
- DVWA-目录遍历-文件包含
开门见山 · 目录遍历 替换成 2. 文件包含可以使用 绝对路径 也可以 3. 可以使用文件包含来包含一个网址,或者是一个shell 远程文件 空字符绕过字符过滤 %00
- PHP语言编写的磁力搜索工具下载BT种子 支持transmission、qBittorrent
磁力搜索网站2020/01/12更新 https://www.cnblogs.com/cilisousuo/p/12099547.html PT种子.BT种子搜索功能 IYUU自动辅种工具,目前能对国 ...
- 配置window下python3环境
功能介绍 整理生信小知识库,一些技巧一些知识. 昨天 以下配置环境基于window操作系统,安装python3版本为例,推荐基础版配置. ! METHOD 1 (基础版) 官网下载对应电脑版本的p ...
- EL表达式和JSTL(三)——EL表达式
在JSP的开发中,为了获取Servlet中存储的数据,通常需要很多的Java代码,这样的做法使的JSP页面非常混乱,为此,JSP2.0中提供了一种EL规范,是一种简单的数据访问语言. 1.初识EL E ...
- 03-string字符串和while循环
目录 03-string字符串和while循环 1. string介绍 2. 字符串的运算 3. 下标及分片 4. 格式化输出 5. f-string格式化输出用法 6. 字符串方法 7. 布尔值,空 ...
- swoole使用内存
//swoole直接操作系统的内存 单线程每秒可执行三百万次 主要用于进程间的数据通信 $swoole_table = new swoole_table(1024);//1024为内创建内存对象所能存 ...
- python通过wakeonlan唤醒内网电脑开机
首先需要pip3 install wakeonlan 然后在电脑需要你的网卡支持网络唤醒计算机. 然后在主板BIOS开启支持唤醒. 在系统网卡属性里选上“允许计算机关闭此设备以节约电源”,“允许此设备 ...
- MACOSX下查看某个端口被哪个程序占用及杀进程方法
sudo lsof -i :9000 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME java 61342 a 313u IPv6 0x11111 ...
- 关于RL78 系列的bootloader
1.充分了解芯片FLASH结构分布,对FLASH进行分区 2.熟练使用FSL库 3.调试中断映射功能 4.调试一种通信方式,UART,CAN等 5.对FLASH进行编程,执行跳转APP程序,调试一个多 ...