我正在使用 gcc 来测试浮点数到无符号 int 之间的一些简单转换。
以下代码段给出结果 0。
const float maxFloat = 4294967295.0;
unsigned int a = (unsigned int) maxFloat;
printf("%un", a);
0 被打印(我相信这很奇怪(。
另一方面,以下代码段:
const float maxFloat = 4294967295.0;
unsigned int a = (unsigned int) (signed int) maxFloat;
printf("%un", a);
打印2147483648我相信这是正确的结果。
我得到 2 个不同的结果会怎样?
如果你首先这样做:
printf("%fn", maxFloat);
你将得到的输出是这样的:
4294967296.000000
假设float
实现为IEEE754单精度浮点类型,则值 4294967295.0 无法由此类型精确表示,因为没有足够的精度位。它可以存储的最接近的值是 4294967296.0。
假设int
(同样unsigned int
(为 32 位,则值 4294967296.0 超出了这两种类型的范围。 当值无法在给定整数类型中表示时,将浮点类型转换为整数类型将调用未定义的行为。
这在 C 标准的第 6.3.1.4 节中有详细说明,该节规定了从浮点类型到整数类型的转换:
1当将实浮点类型的有限值转换为 _Bool 以外的整数类型时,小数部分将被丢弃(即 该值被截断为零(。如果整数部分的值 不能用整数类型表示,行为未定义。61(
。
61( 整数类型的值时执行的余数运算 转换为无符号类型时不需要执行,当值 实际浮点类型转换为无符号类型。因此,范围 可移植的实际浮点值为 (−1, Utype_MAX+1(。
上述段落中的脚注引用了第 6.3.1.3 节,其中详细介绍了整数到整数的转换:
1当整数类型的值转换为 _Bool 以外的其他整数类型时,如果该值可以用新的 类型,它保持不变。
2否则,如果新类型是无符号的,则通过重复添加或减去一个以上的最大值来转换该值 可以用新类型表示,直到值在 新类型。
3否则,新类型是有符号的,并且不能在其中表示值;结果要么是实现定义的,要么是 实现定义的信号被引发。
当相关值为整数时,您在第一个代码段中看到的行为与向无符号类型的超范围转换一致,但是由于要转换的值具有浮点类型,因此它是未定义的行为。
仅仅因为一个实现这样做并不意味着所有人都会这样做。 事实上,如果您更改优化设置,gcc 会给出不同的结果。
例如,在我的机器上使用 gcc 5.4.0,给定以下代码:
float n = 4294967296;
printf("n=%fn", n);
unsigned int a = (unsigned int) n;
int b = (signed int) n;
unsigned int c = (unsigned int) (signed int) n;
printf("a=%un", a);
printf("b=%dn", b);
printf("c=%un", c);
我得到以下结果与 -O0:
n=4294967296.000000
a=0
b=-2147483648
c=2147483648
而这个与 -O1:
n=4294967296.000000
a=4294967295
b=2147483647
c=2147483647
另一方面,如果n
被定义为long
或long long
,你将始终得到以下输出:
n=4294967296
a=0
b=0
c=0
到无符号的转换由上面定位的 C 标准很好地定义,到有符号的转换是实现定义的,gcc 定义如下:
当值无法在对象中表示时,将整数转换为有符号整数类型的结果或引发的信号 该类型(C90 6.2.1.2、C99 和 C11 6.3.1.3(。
为了转换为宽度 N 的类型,该值减少模 2^N 在类型的范围内;没有发出信号。
假设 IEEE 754 浮点数,则4294967295.0
数不能精确存储在float
中。它将存储为4294967296.0
(即 232(。
进一步假设你的unsigned int
有32个值位,这只是一个太大而无法容纳unsigned int
,所以转换的结果是根据C标准未定义的 -0
是一个"合理"的结果。
在你的第二种情况下,你也有未定义的行为,我没有理论在表示层面上发生了什么。事实上,对于 32 位有符号int
来说,这个数字太大了(仍然假设这是你的机器使用的(。
从你问题中的这句话:
打印2147483648我相信这是正确的结果。
我假设你想在内存中看到你的float
的表示形式。强制转换将转换值,因此这不是查看表示的方式。以下代码可以:
int main(void) {
const float maxFloat = 4294967295.0;
unsigned char *floatBytes = &maxFloat;
for (int i=0; i < sizeof maxFloat; ++i)
{
printf("0x%02x ", floatBytes[i]);
}
puts("");
}
在线示例