繁体   English   中英

C中的整数和浮点除法

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM