在C中将float作为整数和整数打印为float时出现奇怪的输出

时间:2014-08-27 19:29:30

标签: c output

以下代码未显示预期的输出,即垃圾值(奇怪的是值被交换)

#include<stdio.h>
int main()
{
    float f = 4.6;
    int d = 7;
    printf("%d %f\n",f,d);
    return 0;
}

输出: 7 4.600000

4 个答案:

答案 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类):

  1. 如果该类为INTEGER,则使用序列%rdi,%rsi,%rdx,%rcx,%r8和%r9的下一个可用寄存器。
  2. 如果类是SSE,则使用下一个可用的向量寄存器,即寄存器 按照从%xmm0到%xmm7的顺序进行。
  3. 当然,您不应该这样做并在编译期间启用警告以捕获它。