【问题标题】:Casting double to int works with constants only将 double 转换为 int 仅适用于常量
【发布时间】:2021-11-14 11:06:30
【问题描述】:

我发现在 C 中转换为 int 的奇怪行为(对我来说)。如果这是一个基本问题,我很抱歉,但我无法找到为什么以下代码会产生意外结果的答案。

#include <stdio.h>
int main(void)
{
    printf("1000 * 0.1 = %d\n", (1000 * 0.1));
    printf("1000 * (10/100) = %d\n", (1000 * (10/100)));
    printf("(int)1000 * 0.1 = %d\n", (int)(1000 * 0.1));
    printf("(int)1000 * (10/100) = %d\n", (int)(1000 * (10/100)));

    return 0;
}

-O0-O3 的结果相同:

1000 * 0.1 = -957043896
1000 * (10/100) = 0
(int)1000 * 0.1 = 100
(int)1000 * (10/100) = 0

我希望前两个结果没有意义(我不知道为什么,但我希望将 double 传递给 int 参数不应该起作用)。然而,3 和 4 之间的差异让我感到困惑。我希望 (10/100) 在编译时计算并呈现与 3 相同的结果。

有人可以向我解释为什么会出现这种结果,以及在这里进行基于整数的除法的正确/安全方法是什么?

【问题讨论】:

  • printf("1000 * 0.1 = %d\n", (1000 * 0.1)); 中,%d 承诺你会通过int,但实际上你已经通过了double。一个好的编译器会发出警告。
  • 第一个printf 是未定义的行为,因为它需要doubles 而格式说明符是int
  • 10/100 是整数数学,将是 0
  • 那么它是否假设整个表达式,即两个部分,都将是整数数学?
  • 假设是错误的词。它整数数学,除非有强制转换或其中一个操作数是浮点常量。

标签: c floating-point printf integer-arithmetic conversion-specifier


【解决方案1】:
printf("1000 * 0.1 = %d\n", (1000 * 0.1));
//                           int    double

int * double 给出双倍。您正在尝试使用"%d" 打印double,它是Undefined Behaviour(通常写为UB)。试试printf("1000 * 0.1 = %f\n", 1000 * 0.1);

printf("1000 * (10/100) = %d\n", (1000 * (10/100)));
//                                int    int int

int / int 进行整数除法,没有小数。 10/100 产生 0(以及 10 的剩余部分)

printf("(int)1000 * 0.1 = %d\n", (int)(1000 * 0.1));
//                                     int    double

双精度 100.0 转换为 int 并自然打印。 请注意,1000 * 0.1 可能会生成 99.999999635264318,而 99.999999635264318 可能会转换为 99

printf("(int)1000 * (10/100) = %d\n", (int)(1000 * (10/100)));
//                                          int    int int

10/100整数除法 ...在这种情况下是 0,与上面的第二条语句相同。

【讨论】:

    【解决方案2】:

    例如printf这两个调用之间存在差异

    printf("1000 * 0.1 = %d\n", (1000 * 0.1));
    printf("1000 * (10/100) = %d\n", (1000 * (10/100)));
    

    在第一次调用中,表达式 1000 * 0.1 的类型为 double,但您使用的转换说明符 %d 不正确,该说明符是为 int 类型的对象设计的。

    在第二次调用中,表达式1000 * (10/100) 确实具有int 类型。请注意,将表达式转换为 int 类型(如 (int)(1000 * (10/100)))是多余的,没有任何意义。相反,您可以编写例如( int )( 1000 * (10.0/100) )。所以这个调用是正确的。但是由于整数运算,原始输出表达式的值等于0。

    【讨论】:

    • 对我来说最大的问题是调用 3 和 4 - 我预计第四次调用也会返回 100。
    • @kiler129 printf 的第 2 次和第 4 次调用没有区别。
    • 不,它没有。它将 10 除以 100,然后 然后 将商 0 转换为浮点数。
    • @kiler129 详细信息:“然后强制将 10.0/100 视为浮点数。” --> 不完全是。 10.0/100double,而不是 float
    • @kiler129 不确定我可以向您推荐什么样的“可消化来源”,但问题是“为什么 10/100 进行整数除法?”是一个很老的人,之前被问过数百次。答案是,至少在 C 中,当你有 x / y 时——事实上,x op y 也是如此,对于 any 运算符 op—— 操作是 总是根据其操作数的类型来执行。编译器永远不会“向外看”来查看您将要对结果做什么。如果你写(float)(i / j),当编译器看到演员表时,已经太晚了。
    猜你喜欢
    • 2012-09-02
    • 2011-05-10
    • 1970-01-01
    • 2011-09-17
    • 2013-06-02
    • 1970-01-01
    • 2014-08-31
    • 1970-01-01
    相关资源
    最近更新 更多