V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
FanyFull
V2EX  ›  问与答

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

  •  
  •   FanyFull · 2022-05-12 15:36:52 +08:00 · 1391 次点击
    这是一个创建于 959 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    求一个解答。

    10 条回复    2022-05-12 17:31:57 +08:00
    duke807
        1
    duke807  
       2022-05-12 15:46:47 +08:00 via Android
    float 型數據被當做 int 數據了唄
    duke807
        2
    duke807  
       2022-05-12 15:48:29 +08:00 via Android
    你看一下對應的 float 數據在內存中的十六進制值就知道了
    villivateur
        3
    villivateur  
       2022-05-12 15:52:48 +08:00
    为啥我的输出是 -268347080

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

    在 x86 下,参数都通过栈传递,结果应该是 double 截断的结果。
    thedrwu
        9
    thedrwu  
       2022-05-12 17:13:40 +08:00 via Android
    x64 和 x86 的 call convention(s)不太一样,x64 下不再 cdecl 了,和那个 float 转换过去的数值关系不大
    msg7086
        10
    msg7086  
       2022-05-12 17:31:57 +08:00 via Android
    God bolt 看一眼汇编?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5365 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 07:16 · PVG 15:16 · LAX 23:16 · JFK 02:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.