以下代码未显示预期的输出,即垃圾值(奇怪的是值被交换)
#include<stdio.h>
int main()
{
float f = 4.6;
int d = 7;
printf("%d %f\n",f,d);
return 0;
}
输出: 7 4.600000
答案 0 :(得分:2)
让我们稍微减少一点:
float f = 4.6;
printf("%d\n", f);
未定义的行为。必须为正确的格式说明符指定正确类型的参数。
未定义的行为可能导致任何结果,包括您所看到的奇怪结果。
现在,您可能会问为什么编译器甚至会生成此代码。因此,让我们看看x86-64程序集中的2个代码:
int main() {
float f = 4.6;
int d = 7;
printf("%d %f\n", d, f);
return 0;
}
int main() {
float f = 4.6;
int d = 7;
printf("%f %d\n", f, d);
return 0;
}
除格式字符串外,这两个代码产生相同的汇编。这可能是因为调用约定要求将浮点数放在不同于整数的寄存器中,或者浮点数应该在堆栈上传递(或者以不同方式处理浮点数和整数的任何其他规则)。
这样可以更清楚地说明为什么你发布的代码仍在产生有用的东西,即使代码刚刚破解。
答案 1 :(得分:1)
与%d
对应的参数必须为int
,与%f
对应的参数必须为double。变量函数的参数经过一些标准转换(因此float
将自动转换为double
),但它们不会自动转换为相应printf
格式说明符的相应类型。
答案 2 :(得分:0)
不是很难理解。 float值在float寄存器中传递,而int值在传统参数堆栈中传递。因此,当引用这些值时,它们会从不同的区域中获取并且神奇地起作用,即使它不应该(也不会在不同的框中)。
答案 3 :(得分:0)
例如,amd64的gcc 4.7.2就是这样做的,因为整数和浮点参数在不同的寄存器中传递。这有效地重新排列了论据。
来自&#34; System V应用程序二进制接口。 AMD64架构处理器补充。草案版本0.99.6&#34; (浮点数具有SSE类):
当然,您不应该这样做并在编译期间启用警告以捕获它。