为啥 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 整数文字一样。

为什么第一行给出编译器警告但第二行没有,即使两者都有从 intfloat 的隐式转换?

【问题讨论】:

我发现除非我使用 -Wconversion 选项,否则我不会收到警告。 【参考方案1】:

在 Mysticial 所写的内容中添加一些内容(这是正确的):您的 C 实现使用 float,它们是 32 位的 32 bits IEEE 754 single precision binary floating-point 和 int。在“你的”int 中,您可以有 31 位数字和 1 位符号。在“你的”浮动中,mantissa 是 24 位,并且有 1 位符号。显然,需要超过 24 位加号才能表示的 ints 不能完全转换为“您的”float。 (我使用“your”来表示“your”编译器,即您正在使用的编译器。C 标准并没有说明floatint 的确切长度。

现在,rand() 可以生成任何int 数字,因此编译器必须向您发出警告。 100 是编译时已知的数字文字,因此编译器可以静态检查该数字是否可转换。

(即使没有确切解释浮点数是如何工作的,您的 int 也是 32 位并且“支持”仅整数。您的 float 是 32 位并且“支持”浮点数。显然浮点数更难来表示(您必须保存小数点所在的位置),因此如果intfloat 的长度相同,则必须支付“价格”。价格是精确的。)

要回复您所做的评论,您可以在与 0“连续”的 float 中精确表示的最大数字(因此 0...数字都可以精确表示)是 16777215(尾数 = 16777215 和指数 = 0)和 16777216(尾数 = 1 和指数 = 24,因为它是 1 * 2 ^ 24)。 16777217 无法准确表示。 16777218 是。

【讨论】:

【参考方案2】:

并非每个int 都可以表示为float。具体来说,如果int 中设置的最高位和最低位之间的位数大于FLT_MANT_DIG - 1(在&lt;float.h&gt; 中定义),则它不能精确地表示为float。 (doubleDBL_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&lt;&lt;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 会警告这种隐式转换?的主要内容,如果未能解决你的问题,请参考以下文章

GCC允许隐式int到指针转换?

为啥这种显式转换的结果与隐式转换的结果不同?

警告:隐式转换在 xcode 6 中会丢失整数精度

为啥 Java 和 C# 没有到布尔值的隐式转换?

为啥隐式符号到字符串的转换会导致 JavaScript 中的 TypeError?

警告:函数的隐式声明