如果 'float'<= INT_MAX 为真,那么为什么 (int)'float' 可能会触发未定义的行为? [英] If 'float'<= INT_MAX is true, then why (int)'float' may trigger undefined behavior?

查看:35
本文介绍了如果 'float'<= INT_MAX 为真,那么为什么 (int)'float' 可能会触发未定义的行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

示例代码 (t0.c):

Sample code (t0.c):

#include <stdio.h>
#include <limits.h>

#define F 2147483600.0f

int main(void)
{
        printf("F            %f\n", F);
        printf("INT_MAX      %d\n", INT_MAX);
        printf("F <= INT_MAX %d\n", F <= INT_MAX);
        if      ( F <= INT_MAX )
        {
                printf("(int)F       %d\n", (int)F);
        }
        return 0;
}

调用:

$ gcc t0.c && ./a.exe
F            2147483648.000000
INT_MAX      2147483647
F <= INT_MAX 1
(int)F       2147483647

$ clang t0.c && ./a.exe
F            2147483648.000000
INT_MAX      2147483647
F <= INT_MAX 1
(int)F       0

问题:

  1. 如果F被打印为2147483648.000000,那为什么F <= INT_MAX是真的?
  2. 在这里避免 UB 的正确方法是什么?
  1. If F is printed as 2147483648.000000, then why F <= INT_MAX is true?
  2. What is the correct way to avoid UB here?

更新.解决方案:

if      ( lrintf(F) <= INT_MAX )
{
        printf("(int)F       %d\n", (int)F);
}

UPD2.更好的解决方案:

UPD2. Better solution:

if      ( F <= nextafter(((float)INT_MAX) + 1.0f, -INFINITY) )
{
        printf("(int)F       %d\n", (int)F);
}

推荐答案

您正在将 int 类型的值与 float 类型的值进行比较.<= 运算符的操作数需要首先转换为通用类型以评估比较.

You're comparing a value of type int with a value of type float. The operands of the <= operator need to first be converted to a common type to evaluate the comparison.

这属于通常的算术转换.在这种情况下,int 类型的值被转换为 float 类型.并且因为有问题的值 (2147483647) 不能完全表示为 float,它导致最接近的可表示值,在本例中为 2147483648.这与宏 F 表示的常量相匹配 转换为,所以比较为真.

This falls under the usual arithmetic conversions. In this case, the value of type int is converted to type float. And because the value in question (2147483647) cannot be represented exactly as a float, it results in the closest representable value, in this case 2147483648. This matches what the constant represented by the macro F converts to, so the comparison is true.

关于将 F 转换为类型 int,因为 F 的整数部分超出了 int<的范围/code>,这会触发未定义行为.

Regarding the cast of F to type int, because the integer part of F is outside the range of an int, this triggers undefined behavior.

C 标准的第 6.3.1.4 节 指示如何执行这些从整数到浮点数以及从浮点数到整数的转换:

Section 6.3.1.4 of the C standard dictates how these conversions from integer to floating point and from floating point to integer are performed:

1 浮点实型的有限值转换为_Bool以外的整数类型时,小数部分被丢弃(即,该值被截断为零).如果值整数部分不能用整数类型表示,行为未定义.

1 When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is discarded (i.e., the value is truncated toward zero). If the value of the integral part cannot be represented by the integer type, the behavior is undefined.

2 当整数类型的值转换为实浮点类型时,如果转换的值可以表示完全在新类型中,它没有改变.如果值被转换后的值在可以表示的范围内但不能准确表示,结果要么是最接近的较高或最接近较低的可表示值,在实现定义的方式. 如果被转换的值是在可以表示的值范围之外,行为未定义.某些隐式转换的结果可能以比这更大的范围和精度表示新类型要求(见 6.3.1.8 和 6.8.6.4)

2 When a value of integer type is converted to a real floating type, if the value being converted can be represented exactly in the new type, it is unchanged. If the value being converted is in the range of values that can be represented but cannot be represented exactly, the result is either the nearest higher or nearest lower representable value, chosen in an implementation-defined manner. If the value being converted is outside the range of values that can be represented, the behavior is undefined. Results of some implicit conversions may be represented in greater range and precision than that required by the new type (see 6.3.1.8 and 6.8.6.4)

第 6.3.1.8p1 节规定了通常的算术转换是如何执行的:

And section 6.3.1.8p1 dictates how the usual arithmetic conversions are performed:

首先,如果任一操作数对应的实数类型为long double,则转换另一个操作数,不改变类型域,到其对应的实际类型为 long double 的类型.

First, if the corresponding real type of either operand is long double, the other operand is converted, without change of type domain, to a type whose corresponding real type is long double.

否则,如果任一操作数对应的实数类型is double,其他操作数被转换,不改变类型域,对应的实际类型为 double 的类型.

Otherwise, if the corresponding real type of either operand is double, the other operand is converted, without change of type domain, to a type whose corresponding real type is double.

否则,如果任一操作数对应的实数类型为float,其他操作数被转换,不改变类型域,对应的实际类型为 float 的类型.

Otherwise, if the corresponding real type of either operand is float, the other operand is converted, without change of type domain, to a type whose corresponding real type is float.

至于在这种情况下如何避免未定义的行为,如果常量F没有后缀,即2147483600.0,那么它的类型为double.这种类型可以准确地表示任何 32 位整数值,因此给定的值不会四舍五入,可以存储在 int 中.

As for how to avoid undefined behavior in this case, if the constant F has no suffix i.e. 2147483600.0 then it has type double. This type can represent exactly any 32 bit integer value, so the given value is not rounded and can be stored in an int.

这篇关于如果 'float'&lt;= INT_MAX 为真,那么为什么 (int)'float' 可能会触发未定义的行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆