V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
hanssx
V2EX  ›  C

跨越 7 年的 long long ago

  •  
  •   hanssx · 2021-06-17 15:41:32 +08:00 · 2670 次点击
    这是一个创建于 1255 天前的主题,其中的信息可能已经有所发展或是发生改变。

    大概 2013 年前后看 C Primer Plus 的时候,出于对 printf 函数原理的理解,写下了下面的代码(ago 变成了 verybig)

    #include <stdio.h>
    int main(void)
    {
        long long verybig = 12345678908642;
        printf("%ld %ld", verybig, verybig);
        return 0;
    }
    

    7 年前的输出:

    1942899938 2874
    

    7 年后的今天的输出( gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04) ):

    $ gcc test2.c -o test -g && ./test                                      
    test2.c: In function ‘main’:
    test2.c:5:15: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘long long int’ [-Wformat=]
         printf("%ld %ld", verybig, verybig);
                 ~~^
                 %lld
    test2.c:5:19: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 3 has type ‘long long int’ [-Wformat=]
         printf("%ld %ld", verybig, verybig);
                     ~~^
                     %lld
    12345678908642 12345678908642%  
    
    

    我已记不清 7 年前用的是什么编译器了,C Primer Plus 书中写的 printf 从右至左压栈却依稀可见~

    7 年后的解释可以参见: https://blog.iret.xyz/article.aspx/printf_magic_float

    难不成 7 年前 printf 是把所有参数都压栈,7 年后是整型和浮点型存寄存器,其他压栈?

    9 条回复    2021-06-25 11:18:09 +08:00
    BrettD
        1
    BrettD  
       2021-06-17 15:44:08 +08:00 via iPhone
    long 的长度在不同平台上不一定相同,所以 ld 可能能用也可能不对
    ysc3839
        2
    ysc3839  
       2021-06-17 15:54:15 +08:00 via Android   ❤️ 2
    long long 要配合 %lld 来用,你那么写大概是 UB,出现任何结果都是符合标准的。
    hanssx
        3
    hanssx  
    OP
       2021-06-17 16:38:15 +08:00
    @ysc3839 你可以去翻看一下 C Primer Plus 书中关于 printf 的介绍
    qwerrewt
        4
    qwerrewt  
       2021-06-17 17:04:42 +08:00   ❤️ 1
    你说的部分是对的,但关键点不对。这个就是 32 位和 64 位的区别,可能你之前是 32 位机器,现在是 64 位。
    验证方法很简单,你加参数-m32 重新编一下,结果应该就和你之前一样了。
    3dwelcome
        5
    3dwelcome  
       2021-06-17 17:24:38 +08:00
    @hanssx 翻过书了,2 楼说的没错。

    书里的例子就不是你首楼写的代码,书里也明确提到:"so use the %ld specifier for long", "the long long types use %lld and %llu"

    那么%ld 是 32 位 long,%lld 是 64 位 long long,两个 GCC 运行结果都没错,是你 7 年前写错了。
    hanssx
        6
    hanssx  
    OP
       2021-06-17 17:46:51 +08:00
    @qwerrewt 老哥厉害,果然如你所说,第一次真切感受到 32 位和 64 位的区别
    ```
    $ gcc -m32 test2.c -o test -g && ./test
    test2.c: In function ‘main’:
    test2.c:5:15: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘long long int’ [-Wformat=]
    printf("%ld %ld", verybig, verybig);
    ~~^
    %lld
    test2.c:5:19: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 3 has type ‘long long int’ [-Wformat=]
    printf("%ld %ld", verybig, verybig);
    ~~^
    %lld
    1942899938 2874%
    ```


    @3dwelcome 你可以试试在 32 位机器上的结果是不是和我一样
    iceheart
        7
    iceheart  
       2021-06-17 19:47:14 +08:00 via Android   ❤️ 1
    %ld 是写 long 型变量的 , %lld 是写 long long 型变量的。
    gcc/clang 64 位模式 long 型长度是 64 位,
    32 位模式长度是 32 位;
    msc 的 32 位 64 位模式 long 型长度都是 32 位。
    Nitroethane
        8
    Nitroethane  
       2021-06-17 22:38:23 +08:00   ❤️ 1
    printf 函数从右向左压栈是因为 x86 架构下函数调用时是通过栈传参,amd64 架构下函数调用是通过寄存器传参。
    jackleeforce3615
        9
    jackleeforce3615  
       2021-06-25 11:18:09 +08:00
    %lu 可以吗
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1323 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 17:43 · PVG 01:43 · LAX 09:43 · JFK 12:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.