具有lld,ld和d类型标识符的size_t变量的printf

时间:2010-03-11 11:37:11

标签: c printf

我写了这个小代码:

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

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

    return 0;
}

我使用 gcc版本4.1.1 20070105(Red Hat 4.1.1-52) i386 GNU / Linux 计算机上运行此功能。这是我得到的输出:

lld=429496729700, ld=100, u=7993461

我可以理解第一个(lld)被打印为垃圾,因为printf尝试打印8个字节(仅signed long long表示lld)变量temp提供4个字节。 但是,我无法理解为什么最后一个标识符u被打印为垃圾 - 而在我的理解中,这是size_t最接近的适用标识符。

这里我假设size_tunsigned int(我的i386签名为4个字节)。

现在,我使用printf行进行了一些调整:

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

我有一个非常好的答案(lld部分除外)。

ld=100, u=100, lld=34331653576851556

有人可以帮助我理解我在这里错过了什么吗?

非常感谢您的帮助!

[旁注:我尝试使用gcc -O[0,2]标签打开/关闭切换优化,但观察结果没有任何差异。]

4 个答案:

答案 0 :(得分:23)

那是因为你在堆栈上推送的是三个32位值,你的格式字符串试图使用其中的四个,或者更准确地说,是一个64位值和两个32位值。

在第一种情况下,lld吸收了两个32位值,ld吸收了第三个值,u得到了堆栈之后发生的任何事情。 ,这可能真的是什么。

当您更改字符串中格式说明符的顺序时,它的工作方式不同,因为ld吸收了第一个32位值,u吸收了第二个和{{1吸收第三个 plus 之后发生在堆栈上的任何事情。这就是为什么你得到不同的价值,这是数据对齐/可用性问题。

您可以使用第一个值查看此操作。 429496729700等于lld,即(2 32 +1)* 100。您的代码段

(4294967296 + 1) * 100

实际上有以下效果:

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

在第二种情况下

What you pass     Stack     What printf() uses
-------------     -----     ------------------
                 +-----+
100              | 100 | \
                 +-----+  = 64-bit value for %lld.
100              | 100 | /
                 +-----+
100              | 100 |    32-bit value for %ld.
                 +-----+
                 | ?   |    32-bit value for %u (could be anything).
                 +-----+

发生以下情况:

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

答案 1 :(得分:9)

您的代码恰当地展示了未定义的行为。请注意,在可变参数的情况下,不会对参数进行类型检查。这是一个必要的明确演员。实际上应该使用以下内容:

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

另外请记住size_t的说明符是z。所以:

 printf("zd=%zd\n", temp);

答案 2 :(得分:0)

您向printf传递错误的字节数。 %lld需要一个更大的整数,在你的情况下,%lld删除它的参数的方式完全搞砸了,因为它会期望一个64位的值。

答案 3 :(得分:0)

在作者的环境中,paxdiablo的答案是合理的。但是,在我的机器(x86_64 Linux)上,我在两个printf行的每种类型中输出了三个“ 100”。因此,printf中的类型不匹配实际上会调用未定义的行为。在特定的运行环境中,也许您会找到怪异的输出结果解释,但这并不是通用的。

基于堆栈的模型并不总是适用,许多现代的调用约定在寄存器中而不是在堆栈中传递前几个普通值。另请参阅in this post提出的奇怪情况。

最后,我们应该避免在printf中使用不匹配类型标识符。当我们遇到printf的奇怪输出时,请不要忘记检查我们是否对所有变量都使用了正确的类型标识符。