C 语言关于 %d 的一个问题

2022-05-12 15:36:52 +08:00
 FanyFull

今天在豆瓣的小组上看到一个问题,大概和 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 是怎么得到的呢?

求一个解答。

1268 次点击
所在节点    问与答
10 条回复
duke807
2022-05-12 15:46:47 +08:00
float 型數據被當做 int 數據了唄
duke807
2022-05-12 15:48:29 +08:00
你看一下對應的 float 數據在內存中的十六進制值就知道了
villivateur
2022-05-12 15:52:48 +08:00
为啥我的输出是 -268347080

环境:WSL1-Ubuntu20.04 ,GCC 9.4.0
jaredyam
2022-05-12 15:53:58 +08:00
bin(1610612736) = 01100000000000000000000000000000
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
duke807
2022-05-12 16:01:46 +08:00
@huntagain2008
@villivateur
因為 %d 對應的 int 數據是 64bits
而傳入的 float 是 32bits
另外 32bits 是來自內存中的其它無關數據,所以可能會變化
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
stein42
2022-05-12 16:55:49 +08:00
在 x86_64 下,整数和指针参数通过通用寄存器传递,浮点数通过浮点数寄存器传递。
这里调用时往浮点数寄存器写入了参数,但函数里面却去通用寄存器里读取,所以结果是随机的。

在 x86 下,参数都通过栈传递,结果应该是 double 截断的结果。
thedrwu
2022-05-12 17:13:40 +08:00
x64 和 x86 的 call convention(s)不太一样,x64 下不再 cdecl 了,和那个 float 转换过去的数值关系不大
msg7086
2022-05-12 17:31:57 +08:00
God bolt 看一眼汇编?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/852434

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX