使用gcc在C中将float转换为unsigned int

标签 c gcc

我正在使用 gcc 测试 float 到 unsigned int 之间的一些简单转换。

下面的一段代码给出了结果0。

const float maxFloat = 4294967295.0;
unsigned int a = (unsigned int) maxFloat;
printf("%u\n", a);

0 被打印出来(我认为这很奇怪)。

另一方面,下面的一段代码:

const float maxFloat = 4294967295.0;
unsigned int a = (unsigned int) (signed int) maxFloat;
printf("%u\n", a);

打印 2147483648,我认为这是正确的结果。

如果我得到 2 个不同的结果会怎样?

最佳答案

如果您首先这样做:

printf("%f\n", maxFloat);

你会得到这样的输出:

4294967296.000000

假设 float 是作为 IEEE754 单精度浮点类型实现的,值 4294967295.0 不能用这种类型精确表示,因为没有足够的精度位。它可以存储的最接近值是 4294967296.0。

假设 int(同样 unsigned int)是 32 位,值 4294967296.0 超出了这两种类型的范围。当值不能用给定的整数类型表示时,将浮点类型转换为整数类型调用 undefined behavior .

这在 C standard 的第 6.3.1.4 节中有详细说明。它指示从浮点类型到整数类型的转换:

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) The remaindering operation performed when a value of integer type is converted to unsigned type need not be performed when a value of real floating type is converted to unsigned type. Thus, the range of portable real floating values is (−1, Utype_MAX+1).

上述段落中的脚注引用了第 6.3.1.3 节,其中详细介绍了整数到整数的转换:

1 When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.

2 Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.

3 Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

您在第一个代码片段中看到的行为与越界转换为无符号类型当所讨论的值是整数时是一致的,但是因为被转换的值具有浮点类型是未定义的行为。

仅仅因为一种实现做到了这一点并不意味着所有的实现都会如此。事实上,如果您更改优化设置,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 定义为 longlong long,您将始终得到以下输出:

n=4294967296
a=0
b=0
c=0

到无符号的转换由上面的 C 标准很好地定义,到有符号的转换是实现定义的,gcc defines如下:

The result of, or the signal raised by, converting an integer to a signed integer type when the value cannot be represented in an object of that type (C90 6.2.1.2, C99 and C11 6.3.1.3).

For conversion to a type of width N, the value is reduced modulo 2^N to be within range of the type; no signal is raised.

关于使用gcc在C中将float转换为unsigned int,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50134795/

相关文章:

c - 为什么使用指针变量时会出现段错误?

c - 在 C 文件中重新声明不透明结构

c - 寻址非整数地址和 sse

c - 查找栈帧大小

c - 如何使用 GCC 编译具有文字属性的内联 C 函数?

windows - 带有自定义链接的 OCaml 编译是否应该在 Windows 中工作(通过 MinGW)?

c - 3rdparty 库中的 typedef 重新定义

c - (分配中的左值无效)当我运行它时发生此错误。这是什么意思?

c - matlab 上的旧 gcc 编译器

linux - 说服 gcc 忽略系统库以支持本地安装的库