使用gcc将浮点转换为C中的无符号整数
我正在使用gcc测试浮点到无符号int之间的一些简单转换 下面的代码给出了结果0使用gcc将浮点转换为C中的无符号整数,c,gcc,C,Gcc,我正在使用gcc测试浮点到无符号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) max
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,我相信这是正确的结果
如果我得到两个不同的结果,会发生什么情况?假设IEEE 754浮点数,则数字
4294967295.0
不能准确地存储在浮点数中。它将存储为4294967296.0
(即232)
进一步假设您的无符号整数
有32个值位,这比无符号整数
大一倍,因此根据C标准,0
的转换结果是“合理”的
在你的第二个例子中,你也有未定义的行为,我不知道在表现层面上发生了什么。事实上,对于32位有符号的int
(仍然假设这是您的机器使用的)来说,这个数字太大了
从你问题中的这句话:
打印2147483648,我相信这是正确的结果
我假设您想查看内存中的浮点值的表示形式。施法将转换值,因此这不是查看表示的方式。以下代码可以:
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("");
}
int main(无效){
常量浮点maxFloat=4294967295.0;
无符号字符*floatBytes=&maxFloat;
对于(int i=0;i
如果您首先执行此操作:
printf("%f\n", maxFloat);
您将得到以下输出:
4294967296.000000
假设浮点
实现为IEEE754单精度浮点类型,则值4294967295.0不能用此类型精确表示,因为没有足够的精度位。它可以存储的最接近的值是4294967296.0
假设int
(同样无符号int
)为32位,则值4294967296.0超出这两种类型的范围。在给定的整数类型中无法表示值时,将浮点类型转换为整数类型调用
第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=%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
或long-long
,则始终会得到以下输出:
n=4294967296
a=0
b=0
c=0
到unsigned的转换由上面的C标准定义,到signed的转换由实现定义,如下所示:
当值不能在对象中表示时,将整数转换为有符号整数类型的结果或所产生的信号
该类型(C90 6.2.1.2、C99和C11 6.3.1.3)
对于转换为宽度N的类型,该值被减少为模2^N
在该类型的范围内;没有发出任何信号
“我相信这是正确的结果。”如果规范没有说明什么应该是正确的,怎么可能“完全错误”呢?@StoryTeller:有一个规范说明了表示424967295并打印它的结果是什么:数学s说他们可以忍受精度下降,但得到零是错误的,这是一个他们希望C更接近数学的说法。例如,将越界浮点值转换为整数的结果可能是饱和,而不是未定义。“他们的说法很简单,我很难理解,而你的回答让人觉得是嘲弄还是粗暴。”埃里克·博斯奇,我强烈反对。关于C是如何工作的,给出了足够多的解释。如果OP坚持认为这是“错误的”,我看不出任何进一步的帮助。@EricPostphil-这就是你错的地方。OP的评论最明确地表明,他们认为自己的实现有问题。正如你自己指出的,他们有理由相信这一点,因为