C/C++:scanf函数的黑科技

事情要从一个问题说起:怎么输出一个double类型数据二进制下的IEEE表示法?
苦思冥想之下决定模拟。恰巧遇到一个问题(哪里来的就无所谓了2333):

double val = 0;
scanf("%f", &val);
printf("%f", val);

输入1.0,输出为0。反复更换了几次输入值,输出均没有变化。
这个错误是很明显的,scanf中格式控制符应该使用lf,至于printf中的格式控制符,f和lf可以混用所以暂且忽略不计。但是造成输出为0的原因是什么?
更改一下代码第一行:
double val = 1;
这样再次运行,输出变成了1.000000
一脸茫然下再改动一点:
double val = 1024;
再运行,发现1024后面会跟着一串小数!
几经思考发现这个和scanf的机制有关,下面是百科对scanf的介绍:

int scanf(const char * restrict format,…);
int scanf(const char * restrict format,…);
函数 scanf() 是从标准输入流stdio (标准输入设备,一般指向键盘)中读内容的通用子程序,可以说明的格式读入多个字符,并保存在对应地址的变量中。

就是我们熟知的scanf,似乎没什么端倪。重点在最后一句:并保存在对应地址变量中。这是很让人迷惑的一句,很容易理解成:保存在对应前面格式控制符的变量中,%d保存进int,%f保存进float,%lf保存进double·····
实则不然。
scanf函数只认识前面的格式控制符,对于后面传入的地址,就只是地址而已,scanf不关心这个地址关联的变量类型,它的工作仅仅是:按照格式控制符读入数据,加以解释按位存入后面传入的地址。“解释”的过程,就是把对应格式控制符的数据按照二进制转换好,整数有原码补码的解释规则,小数有IEEE的解释规则······
上面的说法可能有些抽象,下面举个例子。

int test = 0;
scanf("%c", &test);
printf("%d", test);

这个输出了读入的“字符”的ASCII码值。如果还是不理解,我们再改动一下:
int test = 256;
这样再运行,就会变成256 + ASCII码值。继续改动:
int test = 256 + 128;
运行之后发现,仍然是256+ASCII码值。想必到这里,你应该懂了scanf的机制了。
256在内存中是00······001 0000 0000,scanf会将读入的字符按%c格式解释并填充8位,也就是test对应内存区域末尾8个0所在的位置。
而256+128 = 00······001 1000 0000,scanf在填充时会把末尾的1000 0000填充为读入字符的ASCII码的二进制形式,128也就被无形中抹杀掉了。
再加入小数!

int test = 0;
scanf("%f", &test);
printf("%d", test);

我们知道int和float同属于四字节数据,scanf刚好能填充满test的每一位。输入1.0,输出为:1065353216
转换位二进制:0 01111111 00000000000000000000000
恰好就是float类型的1.0的存储形式!
————————————回到正题!!!———————————————
了解了scanf的机制之后,对于最开始的问题,就会有一个黑科技的解法!代码如下

//scanf黑科技
//为了简便,本次使用C++
#include <iostream>
#include <cstdio>
#include <bitset>
using namespace std;
int main()
{
    long long val = 0;
    scanf("%lf", &val);
    cout << bitset<64>(val) << endl;//此处使用bitset纯属是偷个懒
    return 0;
}

这样对于输入的浮点数,都会以double的IEEE表示法输出!
C的朋友也不用担心,只需把val转换成二进制输出,一个循环即可搞定!
scanf黑科技看起来比较小众、鸡肋,但是解决一些特定问题可能是相当有力的武器!
写的有些粗糙,欢迎各位大犇神犇讨论指正,仍然不懂的同志欢迎讨论!
转载还请注明出处,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值