整型转浮点型会产生警告?

14

很奇怪的是,即使可以进行值转换,将int转换为float的转换总是会提示警告。为什么会这样呢?

int i = 0;
float f = 0; // warning here

// I thought this was an implicit conversion,
// meaning it is convertible with no warnings.
f = i;      // another warning here

警告信息为:

warning C4244: '=' : conversion from 'int' to 'float', possible loss of data

1
将 MAX INT 值赋给 float 类型并查看结果。 - Prince John Wesley
3
float f = 0.0f; // 0 是整数。 - Martin York
使用 f = MAXINT;f = INT_MAX; 都会产生相同的警告。 - user103214
@John:我知道 some_float = MAX_INT; 或者 some_float = some_int 应该会有警告。但是,为什么对于 0 也是必要的呢? - ruslik
@ruslik:糟糕,我刚看到原帖作者在其中一个答案下的评论。显然编译器在初始化和赋值时都会发出警告。虽然这样做是允许的,但警告初始化程序似乎不太聪明。 - Keith Thompson
显示剩余3条评论
4个回答

14
这取决于int类型中有多少位。IEEE754单精度浮点数是一个32位的值,但其中一些位被分配给指数,因此并非所有位都可用于精度。
如果您的int类型比float更精确,则可能会在高端遭受精度损失。
换句话说,它可能无法区分INT_MAXINT_MAX - 1之间的差异。
在这种情况下的解决方案是使用更宽的浮点类型(double),尽管从技术上讲,您可能会发现一个具有256位的int类型的实现,那么您必须找到另一种方法 :-) 这个答案简要介绍了浮点格式的工作原理,包括只有23位用于尾数的精度。

5

我在这里回答了类似的问题:

为什么GCC会对这种隐式转换发出警告?

原因是当一个int被强制转换成float时,需要进行四舍五入,因为float在这种情况下无法包含int的所有精度。

在你的情况下,float只有大约24位的精度。而int有32位的精度,因此,这种转换会导致一些精度损失,因此会出现警告。


存在(并且有)实现,其中float可以容纳类型int的所有值而不会丢失信息——例如,如果intfloat分别为16位和32位,或者为32位和64位。但是,编译器在决定发出警告时当然可以自由使用与特定实现相关的信息。 - Keith Thompson
我确实意识到这一点,因此我在我的答案中插入了“在这种情况下”,因为它并没有被普遍定义为真实的。 - Mysticial

3

只是为了好玩,试试这个代码并看看输出结果是什么(提示:你会期望所有数字都相同,不是吗?):

int i1(INT_MAX), i2;

float f(i1);

i2 = f;

std::cout << i1 << ' ' << f << ' ' << i2 << '\n';

好的,我得到的答案是:

2147483647 2.14748e+009 -2147483648

所以编译器指出类型转换可能出错是对的,但它并不足够聪明以确定是否真的会发生错误,因为这往往只会发生在数值范围的极限情况下。在我看来,最好始终使用static_cast<>,至少能使代码更加清晰,并向编译器表明这正是你想要的。
顺便说一句,我不完全确定上述结果出现的原因。也许其他人可以解释一下!

它给了我两个警告,一个是在初始化浮点数时,另一个是在转换为浮点数时。 - user103214
@user974191:从你最初的问题中并不清楚。我已经更新了它以反映那个信息(虽然我有点惊讶它会对“float f = 0;”发出警告)。请查看我的编辑。 - Keith Thompson

0
// 我以为这是隐式转换,意味着可以无警告地进行转换?
不,那不是它的意思。它只是意味着你可以将一个类型的值分配给另一个类型的对象而不需要显式转换(即强制转换),并且该值将被隐式转换。
在这种情况下,警告可能是适当的。如果int和float都是32位(这是典型但不普遍的),则所有int类型的值都在float范围内,但有许多int类型的值不能在float类型中精确表示。
语言标准要求对于任何违反语法规则或约束条件的翻译单元(源文件)至少发出一条诊断消息。但编译器可以自由地发出任何额外的诊断。

对于额外的编译器诊断信息有一个重要限制——编译器不能发出太多的诊断信息,以至于无法编译符合标准的程序。已经有一些编译器(不知道现在是否还有)会因为一行产生太多警告而崩溃。虽然一行生成数千个警告是不寻常的,但通过宏扩展,符合标准的程序也有可能这样做。 - supercat
@supercat:这同样适用于编译器所做的任何事情,而不仅仅是诊断。你所描述的只是一个编译器错误;通常发出无数警告不会导致编译器崩溃。标准允许编译器因容量限制而失败;它只需要翻译和执行达到所有指定限制的单个程序(C99 5.2.4.1)。 - Keith Thompson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接