我的 C11 标准来自here。这一段说:
实数浮点型的有限值转换为_Bool以外的整数类型时,小数部分被舍弃(即该值被截断为零)。如果整数部分的值不能用整数类型表示,则行为未定义。[61]
和脚注 61 说:
实型浮点型值转无符号型时,整型值转无符号型时的取余运算不需要。因此,便携式实际浮点值的范围是 (−1, U type _MAX+1)
我的困惑主要是关于
unsigned int
。我目前的理解如下:
float a = 3.14;
uint32_t b = (uint32_t)a; // defined, b == 3
float a = -1.23;
uint32_t b = (uint32_t)a; // UB!
float a = 2147483646.0; // defined
uint32_t b = (uint32_t)a; // defined, b == 2147483646
uint8_t c = (uint8_t )a; // UB!
这是正确的吗?
脚注 61 阐明了可以转换为无符号整数类型而没有未定义行为的浮点数范围。
无符号整数类型可以表示[0; Utype_MAX]。因此,此区间内具有整数部分的任何浮点值都可以转换为无符号整数类型,这意味着值
x
其中 x > -1 and x < Utype_MAX+1
。这是脚注 61 最后一部分的声明。
一般规则是,当对无符号整数的运算导致数字超出范围
[0; Utype_MAX]
时,结果将减少模块Utype_MAX+1
(也称为“环绕”)。例如。当将两个 16 位整数相加时,40000+40000=80000 无法用 16 位表示,结果将模数 65536 减少为 14464。
但是,当将浮点数转换为无符号整数时,不需要进行这种环绕。这是脚注 61 中的第一个声明。
范围说明符
(−1, U_type_MAX+1)
是 exclusive(进一步阅读)。也就是说,指定的端点 not 范围本身的一部分。因此,这意味着可以由给定 unsigned
类型表示的浮点数的 inclusive范围的下限是
-1
之后的下一个接近零的浮点数(对于 IEEE-754 -0.999999940395
,这将类似于 float
)。同样,上限将是 U_type_MAX+1
之前的下一个较低的可表示值(将被截断为 U_type_MAX
)。
看你的例子:
3.14
将被截断为 3
– 可以清楚地表示为 uint32_t
.-1.23
将被截断为 -1
– 这不能用 any 无符号类型表示,因此转换是未定义的行为。uint32_t
的最大可表示值是 4294967295
,因此您的 2147483646
的试验值完全可以很好地定义为转换为该类型;但是,uint8_t
的最大值是 255
,因此转换为该类型是未定义的行为。再举一个例子,从
-0.999999940395
到 uint32_t
的转换将被明确定义,因为该值将首先被截断,产生零,它可以用任何无符号类型表示。