C中浮点类型的整数值

pie*_*okr 10 c floating-point integer

#include<stdio.h>
 int main()
 {
   float a;
   printf("Enter a number:");
   scanf("%f",&a);
   printf("%d",a);
   return 0;
 }
Run Code Online (Sandbox Code Playgroud)

gcc在Ubuntu中运行该程序.对于价值观 -

          3.3 it gives value 1610612736 
          3.4 it gives value 1073741824
          3.5 it gives value 0
          3.6 it gives value -1073741824
          4 it gives value 0
          5 it gives value 0
Run Code Online (Sandbox Code Playgroud)

怎么了?为什么打印这些值?我故意这样做,但想了解为什么会这样.详情谢谢!

ken*_*ytm 23

printf函数不知道您传入的格式类型,因为该部分是可变参数.

int printf(const char* format, ...);
//                             ^^^
Run Code Online (Sandbox Code Playgroud)

在C标准中,传递a float将自动提升为double(C11§6.5.2.2/ 6),并且在调用者方面不会做任何其他事情.

在里面printf,因为它不知道那个...东西的类型(§6.7.6.3/ 9),它必须使用来自其他地方的提示 - 格式字符串.既然你已经过去了"%d",它就告诉了函数,这int是预期的.

根据C标准,这会导致不确定的行为(§7.21.6.1/ 8-9),其中包括打印一些奇怪数字的可能性,即故事结束.

但究竟发生了什么?在大多数平台中,a double表示为" IEEE 754 binary64 "格式,而表示floatbinary32格式.您输入的数字将转换为浮点数,只有23位有效值,这意味着数字将近似如下:

3.3 ~ (0b1.10100110011001100110011) × 2¹  (actually: 3.2999999523162842...)
3.4 ~ (0b1.10110011001100110011010) × 2¹  (actually: 3.4000000953674316...)
3.5 = (0b1.11                     ) × 2¹  (actually: 3.5)
3.6 ~ (0b1.11001100110011001100110) × 2¹  (actually: 3.5999999046325684...)
4   = (0b1                        ) × 2²  (actually: 4)
5   = (0b1.01                     ) × 2²  (actually: 5)
Run Code Online (Sandbox Code Playgroud)

现在我们将它转​​换为double,它有53位的重要性,我们必须在这些数字的末尾插入30个二进制"0",以产生例如

3.299999952316284 = 0b1.10100110011001100110011000000000000000000000000000000 ×2¹
Run Code Online (Sandbox Code Playgroud)

这些主要是为了得出这些数字的实际表示,它们是:

3.3 ? 400A6666 60000000
3.4 ? 400B3333 40000000
3.5 ? 400C0000 00000000
3.6 ? 400CCCCC C0000000
4   ? 40100000 00000000
5   ? 40140000 00000000
Run Code Online (Sandbox Code Playgroud)

我建议使用http://www.binaryconvert.com/convert_double.html来查看它如何分解为± m ×2 e格式.

无论如何,我认为你的系统在正常设置下是x86/x86_64/ARM,这意味着数字是使用little-endian格式在内存中布局的,所以传递的参数就像

 byte
  #0   #1   ...          #4   ...            #8 ....
+----+----+----+----+  +----+----+----+----+----+----+----+----+
| 08 | 10 | 02 | 00 |  | 00 | 00 | 00 | 60 | 66 | 66 | 0A | 40 | ....
+----+----+----+----+  +----+----+----+----+----+----+----+----+
 address of "%d"         content of 3.299999952316284
 (just an example)
Run Code Online (Sandbox Code Playgroud)

在里面printf,它使用格式字符串"%d",解析它,然后发现int因为%d需要a,所以从可变参数输入中获取4个字节,即:

 byte
  #0   #1   ...          #4   ...            #8 ....
+ - -+ - -+ - -+ - -+  +====+====+====+====+ - -+ - -+ - -+ - -+
: 08 : 10 : 02 : 00 :  | 00 | 00 | 00 | 60 | 66 : 66 : 0A : 40 : ....
+ - -+ - -+ - -+ - -+  +====+====+====+====+ - -+ - -+ - -+ - -+
 address of "%d"        ~~~~~~~~~~~~~~~~~~~
                        this, as an 'int'
Run Code Online (Sandbox Code Playgroud)

因此,printf将接收0x60000000,并将其显示为十进制整数,即1610612736,这就是您看到该结果的原因.其他数字可以类似地解释.

3.3 ? ... 60000000 = 1610612736
3.4 ? ... 40000000 = 1073741824
3.5 ? ... 00000000 = 0
3.6 ? ... C0000000 = -1073741824 (note 2's complement)
4   ? ... 00000000 = 0
5   ? ... 00000000 = 0
Run Code Online (Sandbox Code Playgroud)