printf
函数不知道您传入的格式类型,因为该部分是可变参数。
int printf(const char* format, ...);
// ^^^
在C标准,传递一个float
会自动提升为double
(C11§6.5.2.2/ 6),而不是其他将在发送方完成。
在printf
里面,因为它不知道...
thingie(§6.7.6.3/ 9)的类型,所以它必须使用其他地方的提示 - 格式字符串。既然你已经通过了"%d"
,它正在告诉函数,预计有一个int
。
根据C标准,这导致了未定义的行为(§7.21.6.1/ 8-9),其中包括打印一些奇怪的数字,故事结束的可能性。
但是究竟发生了什么?在大多数平台中,double
被表示为“IEEE 754 binary64”格式,并且binary32格式表示float
。您所输入的号码将被转换为浮动,只有具有意义的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)
现在我们将它转换为加倍,它具有意义的53位,我们必须在这些数字的末尾插入30个二进制“0”,以产生例如
3.299999952316284 = 0b1.10100110011001100110011000000000000000000000000000000 ×2¹
这些主要是推导这些数字,它们是实际表示:
3.3 → 400A6666 60000000
3.4 → 400B3333 40000000
3.5 → 400C0000 00000000
3.6 → 400CCCCC C0000000
4 → 40100000 00000000
5 → 40140000 00000000
我建议使用http://www.binaryconvert.com/convert_double.html看不出这分解到±米×2 ë格式。
不管怎样,我想你的系统是在正常设置在x86/x86_64的/ ARM,这意味着数字使用little-endian format在内存中摆出来,所以传递的参数会像
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)
里面的printf
,它消耗格式字符串"%d"
,解析它,然后找出该一个int
需要,因为%d,所以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'
所以,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
+1需要时间写出所有这些。 :) – Mysticial 2011-12-29 19:29:27
为了完整起见,有两个有用的补码链接,[Two's Complement - Wikipedia](http://en.wikipedia.org/wiki/Two%27s_complement)和[Two's Complement notes Thomas Finley](http:// tfinley。净/笔记/ cps104/twoscomp.html)。 – mctylr 2011-12-29 20:04:43