struct DummyStruct{
unsigned long long std;
int type;
};
DummyStruct d;
d.std = 100;
d.type = 10;
/// buggy printf, unsigned long long to int conversion is buggy.
printf("%d,%d\n",d.std, d.type); // OUTPUT: 0,100
printf("%d,%d\n", d.type, d.std); // OUTPUT: 10,100
printf("%lld,%d\n",d.std, d.type); // OUTPUT: 100,10
请告诉我为什么在printf中没有正确处理unsigned long long to int转换。我正在使用glibc。
printf中有这个错误吗?
为什么printf不进行内部类型转换?
答案 0 :(得分:13)
%d
参数告诉printf
将相应的参数解释为int
。尝试将%llu
用于long long
。并记住这个reference card。
(所以不,这不是错误)
答案 1 :(得分:5)
它的用法就是问题所在。 除非格式字符串中指定的类型与参数中的类型完全相同,否则事情将无法正常工作。
这是因为编译器将参数按原样推送到堆栈上 没有类型检查或转换。
在运行时,代码将拉取堆栈的值并根据格式字符串中的值前进到下一个对象。如果格式字符串错误,则提前金额不正确,您将获得有趣的结果。
答案 2 :(得分:5)
规则一:您在库或编译器中发现错误的可能性非常非常小。始终假设编译器/库是正确的。
参数通过printf()
(变量参数列表)中的机制传递给<stdarg.h>
,这涉及到堆栈上的一些魔法。
没有详细说明,printf()
做的是假设它必须从堆栈中提取的下一个参数是格式字符串中指定的类型 - 在这种情况下%d
, signed int 。
如果您放入的实际值小于或等于的宽度为int
,则此方法有效,因为内部任何较小的值都会扩展到堆栈的宽度int
通过名为“整数提升”的机制。
但是,如果您传递给printf()
的类型更大而不是int
,则会失败:printf()
被告知%d
})期望一个int
,并从栈中提取适当的字节数(让我们假设32位int
为4个字节)。
对于long long
,我们假设64位值为8个字节,这导致printf()
只获得{{1> 的{em>半 }}。其余的仍然在堆栈中,如果你在格式字符串中添加另一个long long
,会产生非常奇怪的结果。
- )
答案 3 :(得分:1)
使用printf(这是原始C中非常古老的函数之一),编译器不会将格式列表后面的参数强制转换为所需类型,即您需要确保参数列表中的类型与一种格式。
对于大多数其他函数,编译器会将给定参数压缩为声明的类型,但printf,scanf和friends需要 you 告诉编译器确切地跟随哪些类型。