为啥 GCC 会警告这种隐式转换?
Posted
技术标签:
【中文标题】为啥 GCC 会警告这种隐式转换?【英文标题】:Why does GCC warn against this implicit conversion?为什么 GCC 会警告这种隐式转换? 【发布时间】:2011-12-05 19:54:21 【问题描述】:GCC 警告我以下代码包含可能会更改值的隐式转换:
#include <stdlib.h>
float square = rand();
但是,以下内容不会产生任何警告:
float square = 100;
GCC 给出的警告如下:
tests/ChemTests.cpp:17:23: error: conversion to ‘float’ from ‘int’ may alter its value
我不明白为什么前者会发出警告,因为 rand()
已正确声明并返回 int
,就像 100
整数文字一样。
为什么第一行给出编译器警告但第二行没有,即使两者都有从 int
到 float
的隐式转换?
【问题讨论】:
我发现除非我使用-Wconversion
选项,否则我不会收到警告。
【参考方案1】:
在 Mysticial 所写的内容中添加一些内容(这是正确的):您的 C 实现使用 float
,它们是 32 位的 32 bits IEEE 754 single precision binary floating-point 和 int
。在“你的”int
中,您可以有 31 位数字和 1 位符号。在“你的”浮动中,mantissa
是 24 位,并且有 1 位符号。显然,需要超过 24 位加号才能表示的 int
s 不能完全转换为“您的”float
。 (我使用“your”来表示“your”编译器,即您正在使用的编译器。C 标准并没有说明float
或int
的确切长度。
现在,rand()
可以生成任何int
数字,因此编译器必须向您发出警告。 100
是编译时已知的数字文字,因此编译器可以静态检查该数字是否可转换。
(即使没有确切解释浮点数是如何工作的,您的 int
也是 32 位并且“支持”仅整数。您的 float
是 32 位并且“支持”浮点数。显然浮点数更难来表示(您必须保存小数点所在的位置),因此如果int
和float
的长度相同,则必须支付“价格”。价格是精确的。)
要回复您所做的评论,您可以在与 0“连续”的 float
中精确表示的最大数字(因此 0...数字都可以精确表示)是 16777215(尾数 = 16777215 和指数 = 0)和 16777216(尾数 = 1 和指数 = 24,因为它是 1 * 2 ^ 24)。 16777217 无法准确表示。 16777218 是。
【讨论】:
【参考方案2】:并非每个int
都可以表示为float
。具体来说,如果int
中设置的最高位和最低位之间的位数大于FLT_MANT_DIG - 1
(在<float.h>
中定义),则它不能精确地表示为float
。 (double
和 DBL_MANT_DIG - 1
也是如此。)编译器警告您可能会丢失精度,因为 rand()
的声明意味着 rand()
可以返回任何 int
,包括那些不能表示为float
。
gcc 应该足够聪明,知道何时可以精确表示 int
字面量:
float f= 1<<FLT_MANT_DIG; // yes
float g= (1<<FLT_MANT_DIG) - 1; // yes
float h= (1<<FLT_MANT_DIG) + 1; // no
float i= (1<<(FLT_MANT_DIG + 1)); // yes
gcc 应该只针对初始化 h
发出警告。
顺便说一句,如果RAND_MAX
小于或等于(1<<FLT_MANT_DIG) - 1
,即使编译器向您抱怨,您也可以安全地将rand()
分配给float
。
【讨论】:
【参考方案3】:当转换可能导致精度损失时,GCC 会发出此警告。 (换句话说,值可能会被“改变”)
在第一种情况下,rand()
返回一个int
。由于并非所有可以存储在 int
中的值都可以表示为 float
,因此它会发出此警告。
在第二种情况下,100 可以安全地转换为 float
而不会损失任何精度。
【讨论】:
这是否意味着float f = 123456789
会报错?
它不会出错,但应该给出警告。此刻我面前没有 GCC,但我刚刚在 Visual Studio 中对其进行了测试,它给出了警告:warning C4305: 'initializing' : truncation from 'int' to 'float'
以上是关于为啥 GCC 会警告这种隐式转换?的主要内容,如果未能解决你的问题,请参考以下文章