2011-10-12 125 views
9

GCC警告我说下面的代码段包含可能改变的值的隐式转换:为什么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()为p大致声明并返回一个int,就像100整数字面量。

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

+0

我发现我没有得到警告,除非我使用'-Wconversion'选项。 –

回答

14

当铸件可能导致精度损失时,GCC发出此警告。 (换句话说,该值可能被“改变”)

在第一种情况下,rand()返回int。由于并非所有可存储在int中的值均可表示为float,因此它会发出此警告。

在第二种情况下,100可以安全地铸造到float而没有任何精确度损失。

+0

这是否意味着'float f = 123456789'会出错? –

+0

它不会出错,但它应该给出警告。这一刻我没有GCC在我面前,但我只是在Visual Studio中测试它,并给出警告:'警告C4305:'初始化':从'int'截断为'float' – Mysticial

5

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

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

(即使没有解释浮点的工作原理,你的int是32位,只支持整数。你必须保存在某个地方,其中小数点),所以必须有一个“价格”一分钱一分货,如果两个intfloat具有相同的长度,价格是精度。)

对你提出的意见作出回应,在float中与“0”相邻(因此0 ...号码全部可以精确表示)的最大数量是16777215(即尾数= 16777215,exp onent = 0)和16777216(尾数= 1,指数= 24,因为它是1 * 2^24)。 16777217不能完全表示。 16777218是。

0

并非每个int都可以表示为float。具体而言,如果int中设置的最高位和最低位之间的比特数大于FLT_MANT_DIG - 1(在<float.h>中定义),则不能将其精确地表示为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<<FLT_MANT_DIG) - 1,你可以放心地分配rand()float,即使编译器会抱怨你。