前一段时间我正在寻找导致错误的数字数据被写入日志文件的bug。原来问题是代码相当于以下代码:
int main(void) {
struct {
double a;
int b;
} s = { 1, 2 };
printf("%lf\n", s.a);
printf("%lf\n", s.b);
}
正在输出
1.000000
1.000000
显然printf
期望浮点寄存器中的第二个值,而不是堆栈中的第二个值。为了防止将来发生这样的错误,是否应该抛出所有printf参数以确保它们确实属于预期类型?
答案 0 :(得分:5)
根据C99标准。
要打印的实际数据的格式说明符和数据类型不匹配为Undefined behavior
此处b
是和int,因此如果您在第二个"%d"
函数中提供printf()
。
它将打印正确的值,否则为Behavior is Undefined
来自c99
7.19.6
9 If a conversion specification is invalid, the behavior is undefined.242) If any argument is
not the correct type for the corresponding conversion specification, the behavior is
undefined
答案 1 :(得分:2)
是否应该抛出所有printf参数以确保它们确实属于预期类型?
如果类型与预期的类型不同,是。 如果您为编译器启用了警告,它会告诉您。
我怀疑你的行为是相信printf的模板说明符表示你想要一个值显示的样式。这是部分正确的,并且(通过铸造)可以用于主要目的,但的主要目的是指示printf正在考虑什么样的值。
因此,如果你有一个整数类型,你可以使用%d
,但不能使用%f
,因为%f
会是谎言,而且骗到计算机是一项棘手的事情。如果%f
的目的是因为你想要用小数位打印的值,那么你应该把它投出来;这会将整数值正确转换为浮点数。 (您也可以使用%d.000000
,因为整数没有任何分数。)
否则,您应该只使用适合该类型的说明符。
答案 2 :(得分:2)
应该播放所有
printf
参数以确保它们确实存在 期望的类型?
一般情况下。您应该为要传递的每个参数使用格式说明符和参数类型的正确组合。当然,如果你有一个“错误类型”的参数(例如你想用浮点格式说明符打印的int
)那么它需要以某种方式转换,这通常意味着投。但是,在printf
行上散布一大堆演员表“以防万一”在这里不是正确的解决方案。
请注意,编译器无需“理解”printf
(或scanf
或strftime
等)的格式字符串,因此编译器只是必须通过根据一组限制的参数(float
转换为double
,短整数(char
,short
)转换为int
,以及一些其他的事情)。然后归结为printf
来理清你所拥有的东西。当然,如果你没有正确的参数格式规范,那么printf
可能确实在错误的位置查找参数。
因此,总而言之,您需要匹配printf
的参数类型。如果那意味着你偶尔需要一个演员,那么是的,使用演员。但它不应该是“常规的东西”。
答案 3 :(得分:1)
在你的代码printf
中取整数2的内部二进制表示,并将其视为浮点数。
您应该确保放在cast all printf parameters to be sure that they really are of the expected type
中的任何说明符都是正确的类型,而不是printf
。您知道s.b
是int
,为什么要使用%f
?
答案 4 :(得分:0)
老实说,如果更改数据类型 从 struct { 双倍; int b; } s = {1,2}; 至 struct { 双d_a; int n_b; } s = {1,2};
即使您不使用匈牙利表示法,只需在变量中使用某些标记即可提供类型信息。 然后当你输入printf(“%lf \ n”,s.n_b);时,很容易在这里找到陷阱。
C型演员在不同平台上有不良副作用。它们很棘手,很邋.. 如果还有其他方法可以解决问题,请不要使用类型转换。