具有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_t
是unsigned 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位的值。