跨越 7 年的 long long ago

2021-06-17 15:41:32 +08:00
 hanssx

大概 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 年后是整型和浮点型存寄存器,其他压栈?

2672 次点击
所在节点    C
9 条回复
BrettD
2021-06-17 15:44:08 +08:00
long 的长度在不同平台上不一定相同,所以 ld 可能能用也可能不对
ysc3839
2021-06-17 15:54:15 +08:00
long long 要配合 %lld 来用,你那么写大概是 UB,出现任何结果都是符合标准的。
hanssx
2021-06-17 16:38:15 +08:00
@ysc3839 你可以去翻看一下 C Primer Plus 书中关于 printf 的介绍
qwerrewt
2021-06-17 17:04:42 +08:00
你说的部分是对的,但关键点不对。这个就是 32 位和 64 位的区别,可能你之前是 32 位机器,现在是 64 位。
验证方法很简单,你加参数-m32 重新编一下,结果应该就和你之前一样了。
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
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
2021-06-17 19:47:14 +08:00
%ld 是写 long 型变量的 , %lld 是写 long long 型变量的。
gcc/clang 64 位模式 long 型长度是 64 位,
32 位模式长度是 32 位;
msc 的 32 位 64 位模式 long 型长度都是 32 位。
Nitroethane
2021-06-17 22:38:23 +08:00
printf 函数从右向左压栈是因为 x86 架构下函数调用时是通过栈传参,amd64 架构下函数调用是通过寄存器传参。
jackleeforce3615
2021-06-25 11:18:09 +08:00
%lu 可以吗

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

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

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

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

© 2021 V2EX