在C语言中将浮点数作为整数打印和将整数作为浮点数打印时会出现奇怪的输出

3
以下代码未显示预期输出,即垃圾值(奇怪的是值被交换了)。
#include<stdio.h>
int main()
{
    float f = 4.6;
    int d = 7;
    printf("%d %f\n",f,d);
    return 0;
}

输出结果: 7 4.600000


为什么不真的搞乱:printf("%d %f\n",(int)f,(float)d); - David C. Rankin
2
所以不要这样做。一些编译器(特别是gcc)可以在格式字符串为文字时警告printf的参数不匹配,但通常你需要自己正确地调用printf - Keith Thompson
1
这是哪个ABI(处理器,编译器等)?我猜整数和浮点数值会被传递到不同的寄存器中。 - starblue
如果你使用 gcc -Wall -g 进行编译,你会收到一个警告信息,然后你可以在几秒钟内改进你的有问题的源代码。 - Basile Starynkevitch
要么启用所有编译器警告(它应该能捕获到这个问题),要么获取新的编译器。 - chux - Reinstate Monica
显示剩余2条评论
4个回答

2

让我们简化一下:

float f = 4.6;
printf("%d\n", f);

这是“未定义行为”。正确的格式说明符必须给出相应类型的参数。
未定义行为可能导致任何结果,包括您目前看到的奇怪结果。
进一步思考:
现在,您可能会问为什么编译器会生成这段代码。让我们来看看两段代码的x86-64汇编:
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
“%d”对应的参数必须是int类型,“%f”对应的参数必须是double类型。可变参数函数的参数会经过一些标准转换(所以float类型会自动转换为double类型),但它们不会自动转换为相应的printf格式说明符所需的类型。

0

并不难理解。浮点值通过浮点寄存器传递,而整数值则通过常规参数堆栈传递。因此,当引用这些值时,它们从不同的区域获取,并且它们会神奇地工作,尽管它不应该(在不同的计算机上也不会)。


0
例如,gcc 4.7.2适用于amd64,因为整数和浮点参数在不同的寄存器中传递。这有效地重新排序了参数。
来自“System V应用程序二进制接口。AMD64架构处理器补充。草案版本0.99.6”(浮点数具有SSE类):
  1. 如果类是INTEGER,则使用序列%rdi,%rsi,%rdx,%rcx,%r8和%r9的下一个可用寄存器。
  2. 如果类是SSE,则使用下一个可用的矢量寄存器,寄存器按顺序从%xmm0到%xmm7取。
当然,您不应该这样做,并启用警告以在编译期间捕获它们。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接