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

Shr*_*rey 12 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;
}
Run Code Online (Sandbox Code Playgroud)

我在带有gcc版本4.1.1 20070105(Red Hat 4.1.1-52)i386 GNU/Linux机器上运行它.这是我得到的输出:

lld=429496729700, ld=100, u=7993461
Run Code Online (Sandbox Code Playgroud)

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

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

现在,我对该printf线进行了一些调整:

...
printf("ld=%ld, u=%u, lld=%lld\n", temp, temp, temp);
...
Run Code Online (Sandbox Code Playgroud)

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

ld=100, u=100, lld=34331653576851556
Run Code Online (Sandbox Code Playgroud)

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

非常感谢您的帮助!

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

pax*_*blo 23

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

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

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

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

printf("lld=%lld, ld=%ld, u=%u\n", temp, temp, temp);
Run Code Online (Sandbox Code Playgroud)

实际上有以下效果:

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).
                 +-----+
Run Code Online (Sandbox Code Playgroud)

在第二种情况下

printf("ld=%ld, u=%u, lld=%lld\n", temp, temp, temp);
Run Code Online (Sandbox Code Playgroud)

发生以下情况:

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


dir*_*tly 9

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

 printf("lld=%lld, ld=%ld, u=%u\n", 
         (unsigned long long)temp, 
         (unsigned long)temp, 
         (unsigned int)temp);
Run Code Online (Sandbox Code Playgroud)

顺便一下,请记住size_tis 的说明符z.所以:

 printf("zd=%zd\n", temp);
Run Code Online (Sandbox Code Playgroud)