# 为什么 C 语言中 int 数据使用 %f 打印输出结果为 0?

前言

最近在社团出招新试题,朋友出了一道 C 语言题,我在帮写答案的时候发现这个题目有点意思。

题目如下:

int main(){
     int i=1;
    printf("%f\n",i);   
}

输出:

-1

解释出现这种情况的原因?

%f 是把数据以 double 格式打印出来的, intdouble 的格式不一样。不过,C99 之后可以也可以使用 %lf 来输出 double

int 是准确值,而 double 是精确值,准确转精确会精度丢失。 int 的存储结构是:一个符号位 31 个指数位。 double 的存储结构是: 1 个符号位, 11 个指数位, 52 个尾数。格式化字符串不会帮你做类型转换,并不会智能的将 int 转为 double ,它会按照计算机内部的数据表示忠实反映结果, 只是将 1 在内存中的二进制形式按照 double 存储标准来解析。

%f 寻 64 位内存, int 只有 32 位,所以会在后面全补 0 直到补满 64 位。

对于 64 位的浮点数,最高的 1 位是符号位 S,接着的 11 位是指数 E,剩下的 52 位为有效数字 M。

img

对于 32 位的浮点数,最高的 1 位是符号位 s,接着的 8 位是指数 E,剩下的 23 位为有效数字 M。

·

根据国际标准 IEEE 754,任意一个二进制浮点数 V 可以表示成下面的形式:

V=(-1)^{s}*M*2^

  • (1)s(-1) ^ s 表示符号位,当 s=0,V 为正数;当 s=1,V 为负数。

  • M 表示有效数字,大于等于 1,小于 2。

  • 2E2^E 表示指数位。

%f 是把数据以 double 格式打印出来的, intdouble 的格式不一样。

1 ≤ M < 2,也就是说,M 可以写成 1.xxxxxx 的形式,其中 xxxxxx 表示小数部分。IEEE 754 规定,在计算机内部保存 M 时,默认这个数的第一位总是 1,因此可以被舍去,只保存后面的 xxxxxx 部分。

指数 E 还可以再分成三种情况:

**(1)e 不全为 0 或不全为 1。** 这时,浮点数就采用上面的规则表示,即指数 E 的计算值减去 127(或 1023,这是在 double 的情况下,下同),得到真实值,再将有效数字 M 前加上第一位的 1。

**(2)e 全为 0。** 这时,浮点数的指数 E 等于 1-127(或者 1-1023),有效数字 M 不再加上第一位的 1,而是还原为 0.xxxxxx 的小数。这样做是为了表示 ±0,以及接近于 0 的很小的数字。

**(3)e 全为 1。** 这时,如果有效数字 M 全为 0,表示 ± 无穷大(正负取决于符号位 s);如果有效数字 M 不全为 0,表示这个数不是一个数(NaN)。

这题符合第二个规则,所以最终公式:

V=(-1)^0*2^{-51}*2^{-1022}=2^

$M = $

210732^{-1073} 约等于 10^

验证:出现第一个非零的数确实是在 300 多的位置。

image-20220922175436498