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

我写了这个小代码:

#include  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 )被打印为垃圾,因为当变量temp只有4个字节可用时, printf尝试打印8个字节(对于lld所表示的有signed long long )。 但是,我无法理解为什么最后一个标识符, 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]标签打开/关闭切换优化,但观察结果没有任何差异。]

那是因为你在堆栈上推送的是三个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); 

实际上有以下效果:

 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); 

发生以下情况:

 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). | ? | / +-----+ 

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

  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); 

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