gpt4 book ai didi

c - 具有 lld、ld 和 d 类型标识符的 int 变量的 printf

转载 作者:行者123 更新时间:2023-11-30 20:29:15 25 4
gpt4 key购买 nike

正如我所想,printf中的%d将从堆栈中读取sizeof(int),%ld将从堆栈中读取sizeof(long),以此类推%lld。我写了这个代码片段:

##############printf1.c
#include <stdio.h>

int main()
{
int a = 1, b = 2;
long la = 1, lb = 2;
long long lla = 1, llb = 2;

printf("a=%d, b=%d\n", a, b);
printf("a=%ld, b=%ld\n", a, b);
printf("a=%lld, b=%lld\n", a, b);

printf("la=%d, lb=%d\n", la, lb);
printf("la=%ld, lb=%ld\n", la, lb);
printf("la=%lld, lb=%lld\n", la, lb);

printf("lla=%d, llb=%d\n", lla, llb);
printf("lla=%ld, llb=%ld\n", lla, llb);
printf("lla=%lld, llb=%lld\n", lla, llb);

return 0;
}

我机器上的输出是:

$ ./printf1
a=1, b=2
a=1, b=2
a=1, b=2
la=1, lb=2
la=1, lb=2
la=1, lb=2
lla=1, llb=2
lla=1, llb=2
lla=1, llb=2

这是怎么发生的?我认为如果变量类型和类型标识符不匹配,应该会有一些垃圾输出。我的机器:

$ uname -a
Linux cu01 3.10.0-693.el7.x86_64 #1 SMP Tue Aug 22 21:09:27 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

我的海湾合作委员会:

$ gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-16)
PS:我读过这篇文章: printf of a size_t variable with lld, ld and d type identifiers 。但是笔者的问题在我的测试中并没有出现。至于作者的代码:

##############printf2.c
#include <stdio.h>
int main()
{
size_t temp;
temp = 100;

printf("lld=%lld, ld=%ld, u=%u\n", temp, temp, temp);
printf("ld=%ld, u=%u, lld=%lld\n", temp, temp, temp);

return 0;
}

我机器上的输出结果始终是“正确的”:

$ ./printf2
lld=100, ld=100, u=100
ld=100, u=100, lld=100

有人可以解释一下吗?非常感谢您的帮助!

最佳答案

这确实是由于这些值传递给 printf 的方式以及它们的读取方式的组合而发生的。因此,首先,使用 d 说明符将其传递给 printf 时获得正确结果的原因是它只读取 8 字节整数中的前 4 个字节,恰好是这样数字 1 只占用一个字节,因此无论读取多少字节,它都会打印 1。这是一种简单的方法来可视化它。

这是你的长(和长长)数字在二进制中的样子

00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001
|-----------------------------------|

上面显示了当您使用 d 作为说明符传递它时读取的位(如果您要传递 ldlld) > 作为说明符,它将读取剩余的 4 个字节,但由于它们都是前导零,这显然不会影响打印结果。同样的概念也适用于数字 2。尝试用 LONG_MAX 替换 lalla 的值,您会注意到它会打印 -1d 说明符一起使用时。请注意,此行为是未定义的,因为它取决于系统的字节顺序,并且不会在所有系统上发生,这只是您的系统上最有可能发生的情况。

现在,为什么这不会破坏堆栈?如果我们不诚实地了解传递给堆栈的东西的大小,显然应该这样做,对吗?既然您使用的是 Linux 系统,您的机器使用的是 System V abi,​​它在调用约定中指定前几个参数将使用寄存器传递,因此在这种情况下实际上没有任何内容被推送到堆栈上,并且全部都是从寄存器中读取的。如果您想了解更多信息,这里有更多信息 https://wiki.osdev.org/Calling_Conventions

值得注意的是,这会在不同的机器上产生不同的结果,这显然就是为什么它被称为未定义行为,以及为什么你不应该依赖它或在代码中使用它,特别是当它很容易不使用时在这样的情况下。

关于c - 具有 lld、ld 和 d 类型标识符的 int 变量的 printf,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58579458/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com