关于C语言中printf函数“输出歧视”的问题
关于C语言中printf函数“输出歧视”的问题
问题描述
昨天晚上被问到一个问题,为什么在同一个printf函数中两次输出一个double型变量会得不到正确的结果。具体代码大致如下:
#include <stdio.h>
int main()
{
int a;
double b;
double result;
printf("Please input a: ");
scanf("%d", &a);
printf("Please input b: ");
scanf("%lf", &b);
printf("\n");
result = a * b;
printf("result_int: %d\nresult_double: %f\n", result, result);
return 0;
}
看主函数的第18行语句,其中result作为一个double型变量,被以整型和浮点型分别输出了一次,按照正常思路,输出应该是下面这样:
Please input a: 12
Please input b: 12.3
result_int: 858993460
result_double: 147.600000
即前一个按整型输出时,会按照double型低32位的数据,输出一个不期望的整数。
但是第二次输出时,则会按照其正确的形式(64位8字节double类型)输出一个预期中的浮点数:147.600000。
结果却大出意料,实际输出是下面这样:
Please input a: 12
Please input b: 12.3
result_int: 858993460
result_double: 0.000000
探索问题原因
这样的结果让人很意外,第一时间就想到了是否是因为result本身出了问题,所以在原程序后加入了一句printf("\n%f\n", result);来确认result是否发生了意料之外的变化。
但是很显然,并不是result出了问题,因为单独输出的result依然是正常的147.600000。
那么接下来,既然result本身没有问题,就应当想到是否在输出上出了问题。比如很显然地,%d格式是标准的Int型输出格式,正常来讲应该是32位数据,而double则是64位数据,是否是这里出了问题呢?
比如在同一句输出里面,对同一个变量多次不完整输出,导致了其地址的递进式输出。
当然,到此时,这只是我的一种猜测。
要验证这个想法,最简单的莫过于直接查看内存内容。
如图
转换为4字节整数显示结果为
与输出
result_lower_32 = 858993459
result_higher_32 = 1080193843
resule_now = 147.600000
相符。
到此,产生这一问题的原因已经弄清楚了,并且最终问题应该是出在printf函数的定义中,看来还是C语言基础不牢,今天开始有必要重新学习,认真研究其每个细节。
另一种研究方法
实际上一开始因为不太熟悉VS的调试操作,并没能很快地在调试界面找到方法查看具体变量的内存地址及其内容,原因一则是很久没有用C语言了,二则当初学的时候也没有认真,所以验证这个问题的过程十分艰辛,
中间还自己写了个函数想要输出数据的二进制格式,但是这个函数针对整型时工作正常,换成double型之后,由于没想到办法对double型和unsigned long long型直接进行位运算,所以迫不得已对double型数据进行了强制类型转换,最终发现强制类型转换会导致数据变化,无法保持其原型,所以这一思路作废。就此略过不表。
后来想起来C语言中可以对数据直接按16进制格式输出,故设计了如下程序进行尝试。
#include <stdio.h>
int main()
{
//该系统中,double为64位8字节,int和long为32位4字节。
//且为小端系统,即低位数据存储在内存的低位地址中。
double b;
printf("Please input the values of b:\n");
scanf("%lf", &b);
printf("\n");
printf("These are two parts of b:\n");
printf("\tlower byte = \t%#x\n\thigher byte = \t%#x\n\n", b, b);
printf("This is the whole b:\n");
printf("\t%#llx\n", b);
return 0;
}
输出如下(输入为12.3)
Please input the values of b:
12.3
These are two parts of b:
lower byte = 0x9999999a
higher byte = 0x40289999
This is the whole b:
0x402899999999999a
问题结论
从上述两种研究方法的结果,我们可以明显看到,在同一个输出格式字符串中,倘若针对某一个待输出量的转换说明不足以对应其所有的数据位,则printf函数仅仅按照转换说明对应的数据位数,从低到高,依次输出。
所以对于介于初学和中级之间的学习者而言,研究stdio.h头文件的源码函数很有必要的。
关于C语言中printf函数“输出歧视”的问题的更多相关文章
- c语言中printf()函数中的参数计算顺序
今天看到了一个关于printf()函数计算顺序的问题,首先看一个例子: #include<stdio.h> int main() { printf("%d---%d---%d&q ...
- c语言中的c语言中realloc()函数解析
c语言中realloc()函数解析 真是有点惭愧,这些内容本应该很早就掌握的,以前只是糊里糊涂的用,不知道在内存中具体是怎么回事,现在才弄清楚. realloc(void *__ptr, size_t ...
- C语言中system()函数的用法总结(转)
system()函数功能强大,很多人用却对它的原理知之甚少先看linux版system函数的源码: #include <sys/types.h> #include <sys/wait ...
- 使用C语言中qsort()函数对浮点型数组无法成功排序的问题
一 写在开头 1.1 本节内容 本节主要内容是有关C语言中qsort()函数的探讨. 二 问题和相应解决方法 qsort()是C标准库中的一个通用的排序函数.它既能对整型数据进行排序也能对浮点型数据进 ...
- R语言中apply函数
前言 刚开始接触R语言时,会听到各种的R语言使用技巧,其中最重要的一条就是不要用循环,效率特别低,要用向量计算代替循环计算. 那么,这是为什么呢?原因在于R的循环操作for和while,都是基于R语言 ...
- (转)C语言中Exit函数的使用
C语言中Exit函数的使用 exit() 结束当前进程/当前程序/,在整个程序中,只要调用 exit ,就结束return() 是当前函数返回,当然如果是在主函数main, 自然也就结束当前进程了,如 ...
- C语言中qsort函数用法
C语言中qsort函数用法-示例分析 本文实例汇总介绍了C语言中qsort函数用法,包括针对各种数据类型参数的排序,非常具有实用价值非常具有实用价值. 分享给大家供大家参考.C语言中的qsort ...
- C笔记01:关于printf函数输出先后顺序的讲解
关于printf函数输出先后顺序的讲解!! 对于printf函数printf("%d%d\n", a, b);函数的实际输出顺序是这样的先计算出b,然后再计算a,接着输出a,最后再 ...
- C语言中malloc函数返回值是否需要类型强制转换问题
1. 在C语言中, 如果调用的函数没有函数原型, 则其返回值将默认为 int 型. 考虑调用malloc函数时忘记了 #include <stdlib.h>的情况 此时malloc函数返回 ...
随机推荐
- 1.2celery的安装
我们可以使用python的包管理器pip来安装: pip install -U Celery 也可从官方直接下载安装包:https://pypi.python.org/pypi/celery/ tar ...
- PHP class 继承
1.执行结果 成员名 成员修饰符 方法名 方法修饰符 执行结果 name private setName private 在构造函数函数中执行父类私有方法,子类未能覆盖private成员变量和方法,修 ...
- struct 方法使用
struct _Worker { _Worker() { pWokerbase=NULL; hThread=INVALID_HANDLE_VALUE; pListConn=NULL; } struct ...
- 【291】Python 中字符串添加到剪贴板
参考:如何使用Python将字符串复制到Windows上的剪贴板上? 实现代码如下: from Tkinter import Tk r = Tk() r.withdraw() r.clipboard_ ...
- accept巨坑
在做node.js时, 我们要把一个资源发送回前端,需要用到以下一句: res.setHeader('Content-Type', mime ); mime,全称即Multipurpose Inter ...
- ionic中的后退方法
1)$ionicHistory.goBack(); 2)$ionicNavBarDelegate.back(); 个人感觉: 1)$ionicHistory.goBack()会按照html历史来后退 ...
- 在VMware中为Red Hat配置静态ip并可访问网络-Windows下的VMware
首先确保虚拟网卡(VMware Network Adapter VMnet8)是开启的,然后在windows的命令行里输入“ipconfig /all”,找到VMware Network Adapte ...
- sudo apt install libreadline-dev Reading package lists... Error!
luo@luo-ThinkPad-W540:~$ luo@luo-ThinkPad-W540:~$ luo@luo-ThinkPad-W540:~$ luo@luo-ThinkPad-W540:~$ ...
- npm link和react native的问题
问题说明: 需要自己开发一个ReactNative插件,这个插件在独立git仓库,那么怎么把这个插件安装到主项目的依赖里,并且方便对插件的修改调试 方案一: 把插件发布到npm仓库,每次主项目通过np ...
- linux下安装sz/rz命令
参考 https://blog.csdn.net/kobejayandy/article/details/13291655