如果你首先这样做:
printf("%f\n", maxFloat);
您将得到的输出是这样的:
4294967296.000000
假设一个float
被实现为 IEEE754 单精度浮点类型,值 4294967295.0 无法用此类型精确表示,因为没有足够的精度位。最接近的值can商店是 4294967296.0。
假设一个int
(同样地unsigned int
) 是 32 位,值 4294967296.0 超出了这两种类型的范围。当值无法用给定整数类型表示时,将浮点类型转换为整数类型调用未定义的行为 https://en.wikipedia.org/wiki/Undefined_behavior.
这在第 6.3.1.4 节中有详细介绍。C标准 http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf这规定了从浮点类型到整数类型的转换:
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.61)
...
61) 整数类型值时执行的余数运算
当值为以下时,无需执行转换为无符号类型
实浮点类型转换为无符号类型。因此,范围为
可移植的实浮点值为(−1, Utype_MAX+1)。
上述段落中的脚注引用了第 6.3.1.3 节,其中详细介绍了整数到整数的转换:
1当一个整数类型的值转换为_Bool以外的其他整数类型时,如果该值可以用新的值表示
类型,它没有改变。
2否则,如果新类型是无符号的,则通过重复加或减 1 来转换该值。
可以用新类型表示,直到该值在以下范围内
新类型。
3否则,新类型是有符号的,并且该值无法在其中表示;结果要么是实现定义的,要么是
引发实现定义的信号。
您在第一个代码片段中看到的行为与到无符号类型的超出范围转换一致当相关值是整数时,但是因为要转换的值具有浮点类型,所以这是未定义的行为。
仅仅因为一种实现做到了这一点并不意味着所有实现都会这样做。事实上,如果更改优化设置,gcc 会给出不同的结果。
例如,在我使用 gcc 5.4.0 的机器上,给出以下代码:
float n = 4294967296;
printf("n=%f\n", n);
unsigned int a = (unsigned int) n;
int b = (signed int) n;
unsigned int c = (unsigned int) (signed int) n;
printf("a=%u\n", a);
printf("b=%d\n", b);
printf("c=%u\n", c);
我使用 -O0 得到以下结果:
n=4294967296.000000
a=0
b=-2147483648
c=2147483648
和 -O1 一起使用:
n=4294967296.000000
a=4294967295
b=2147483647
c=2147483647
如果另一方面n
定义为long
or long long
,你总是会得到这样的输出:
n=4294967296
a=0
b=0
c=0
如上所述,到无符号的转换由 C 标准明确定义,而到有符号的转换是实现定义的,其中海湾合作委员会定义 https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html如下:
当值无法在对象中表示时,将整数转换为有符号整数类型的结果或引发的信号
该类型(C90 6.2.1.2、C99 和 C11 6.3.1.3)。
为了转换为宽度 N 的类型,该值会减少模 2^N
在该类型的范围内;没有发出任何信号。