[英]Integer and Float divisions in C
任何人都可以告诉我为什么会这样......我用最新的GCC编译器编译并执行它。
请不要给出“%f代替%d”等建议。
#include <stdio.h>
int main(void)
{
printf("%d" , 3.0 / 2.0);
return 0;
}
预期产出:1
输出:0
#include <stdio.h>
int main(void)
{
printf("%f" , 3 / 2);
return 0;
}
预期产出:1.000000
提供输出:0.000000
在第一种情况下,当格式说明符期望int
时,传递double
类型的表达式;在第二种情况下,当格式说明符期望double
时,传递类型为int
的表达式。
使用错误的格式说明符会调用C标准规定的未定义行为 ,这意味着您无法可靠地预测程序的行为方式。 不同的编译器可能以不同的方式显示未定义的行为,以及同一编译器上的不同优化设置。
试图推断未定义的行为是没有用的。 只需确保您的程序运行良好,在这种情况下意味着使用正确的格式说明符。
话虽这么说,x86系统的编译器通常在浮点寄存器中传递浮点参数,而整数在堆栈上传递。 因此,当printf
尝试读取给定类型的参数时,它最终会读取它所看到的任何垃圾,因为实际参数根本不存在。
计算平台 - 一起工作的硬件和软件 - 定义如何将参数传递给函数。 如何传递参数的规范是通常称为应用程序二进制接口(ABI)的规范的一部分。
关于如何传递参数的细节可能取决于几个因素,包括:
论证应该通过的方式可能包括:
表达式3 / 2
具有int
类型。 它将以ABI为int
参数指定的方式传递。 当你在printf
格式中指定%f
时, printf
需要一个double
,而printf
在ABI为double
指定的位置查找参数。
因此,在printf("%f" , 3 / 2);
,无法保证printf
甚至可以看到传递的int
值。 它可能从错误的内存中获取数据或完全注册。
如果printf
确实获取了int
值的数据,它将把这些字节解释为它们是double
值。 字节值在编码int
时具有与编码double
时不同的含义。 因此,编码int
值为1的字节中的值在编码double
值时不会编码1。 因此,即使printf
在为%f
格式化double
,获取int
值为1的字节,它产生的字符也不可能是“1”。
C标准定义了如何使用printf
及其格式说明符,以便ABI可以工作。 当您违反有关将参数类型与格式说明符匹配的C规则时,C标准不会定义哪种行为结果。 它让你受C实现的支配。 从历史上看,这意味着你违反了ABI,由于我上面描述的原因,程序会破坏。 随着时间的推移,编译器在优化和其他程序转换方面变得更加积极,结果违反C标准的规则可以以更令人惊讶的方式改变程序行为。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.