今天在豆瓣的小组上看到一个问题,大概和 stackoverflow 上面这个问题类似。
问题描述:
使用 %d
打印 double 类型的值,C 语言是怎么把值转成十进制的数的。
代码如下:
int main()
{
float a = 3.3f;
int b = 2;
printf("%d", a * b);
}
运行结果是 1610612736
,和 stackoverflow 上面题主的运行结果一样,
我的运行环境是:Windows10 ,mingw gcc version 11.3.0 。
对于上面的代码,我知道 a 和 b 相乘时,int 类型的 b 会被转换成 float 类型,然后在 printf 函数里面,其相乘的结果又会被转成 double ,然后最终被打印的时候其长度又会被截掉一半。我理解正确的用法是使用 %d
或 %ld
,可是在使用 %d
这个错误用法的情况下,结果值 1610612736
是怎么得到的呢?
求一个解答。
1
duke807 2022-05-12 15:46:47 +08:00 via Android
float 型數據被當做 int 數據了唄
|
2
duke807 2022-05-12 15:48:29 +08:00 via Android
你看一下對應的 float 數據在內存中的十六進制值就知道了
|
3
villivateur 2022-05-12 15:52:48 +08:00
为啥我的输出是 -268347080
环境:WSL1-Ubuntu20.04 ,GCC 9.4.0 |
4
jaredyam 2022-05-12 15:53:58 +08:00
bin(1610612736) = 01100000000000000000000000000000
|
5
huntagain2008 2022-05-12 15:55:13 +08:00
小白我在 Arch Linux 上新建 aaa.c ,用 vim 输入了楼主的代码,然后 cc aaa.c 进行编译得到 a.out
$ ./a.out 64705400 $ ./a.out 1530287528 $ ./a.out 2089164296 $ ./a.out -2046470840 |
6
duke807 2022-05-12 16:01:46 +08:00 via Android
@huntagain2008
@villivateur 因為 %d 對應的 int 數據是 64bits 而傳入的 float 是 32bits 另外 32bits 是來自內存中的其它無關數據,所以可能會變化 |
7
o00O00o 2022-05-12 16:42:36 +08:00
(double) a * b = 0x40 1a 66 66 60 00 00 00,
截断四个字节后 0x60 00 00 00 = 1610612736 |
8
stein42 2022-05-12 16:55:49 +08:00
在 x86_64 下,整数和指针参数通过通用寄存器传递,浮点数通过浮点数寄存器传递。
这里调用时往浮点数寄存器写入了参数,但函数里面却去通用寄存器里读取,所以结果是随机的。 在 x86 下,参数都通过栈传递,结果应该是 double 截断的结果。 |
9
thedrwu 2022-05-12 17:13:40 +08:00 via Android
x64 和 x86 的 call convention(s)不太一样,x64 下不再 cdecl 了,和那个 float 转换过去的数值关系不大
|
10
msg7086 2022-05-12 17:31:57 +08:00 via Android
God bolt 看一眼汇编?
|