开发者

Why does GCC warn against this implicit conversion?

开发者 https://www.devze.com 2023-04-12 22:28 出处:网络
GCC warns me that the following piece of code contains an implicit conversion that may change a value:

GCC warns me that the following piece of code contains an implicit conversion that may change a value:

#include <stdlib.h>
float square = rand();

However, the following does not yield any warning:

float square = 100;

The warning given by GCC is a follows:

t开发者_如何学Pythonests/ChemTests.cpp:17:23: error: conversion to ‘float’ from ‘int’ may alter its value

I don't understand why the former would give a warning, since rand() is properly declared and returns an int, just as the 100 integer literal.

Why does the first line give a compiler warning but not the second, even though both have an implicit conversion from intto float?


GCC emits this warning when a loss of precision may result from the cast. (in other words, the value may be "altered")

In the first case, rand() returns an int. Since not all values that can be stored in an int are representable as a float, it will emit this warning.

In the second case, 100 can be safely casted to a float without any precision loss.


To add something to what Mysticial wrote (that is correct): your implementation of C uses float that are 32 bits IEEE 754 single precision binary floating-point and int that are 32 bits. In "your" int you can have 31 bits of number and 1 bit of sign. In "your" float the mantissa is 24 bits and there is 1 bit of sign. Clearly ints that need more than 24 bits plus sign to be represented can't be converted exactly to "your" float. (I use the "your" to represent "your" compiler, the compiler you are using. The C standard doesn't tell the exact length of float or int).

Now, the rand() can generate any int number, so the compiler has to give you the warning. The 100 is a numeric literal that is known at compile time, so the compiler can statically check if that number is convertible.

(even without explaining exactly how floating points work, your int is 32 bits and "supports" only integer numbers. Your float is 32 bits and "supports" floating point numbers. Clearly floating point numbers are more difficult to represent (you have to save somewhere where the decimal point is), so there must be a "price" you pay if both int and float have the same length. The price is precision.)

To respond to the comment you made, the maximum number you can represent exactly in a float that is "contiguous" to 0 (so that 0...number are all exactly representable) are 16777215 (that has mantissa = 16777215 and exponent = 0) and 16777216 (that has mantissa = 1 and exponent = 24, because it's 1 * 2 ^ 24). 16777217 isn't representable exactly. 16777218 is.


Not every int can be represented as a float. Specifically, if the number of bits between the highest and lowest bit set in an int is greater than FLT_MANT_DIG - 1, defined in <float.h>, it cannot be represented precisely as a float. (Same goes for double and DBL_MANT_DIG - 1.) The compiler warns you that there's a potential loss of precision because the declaration of rand() means that rand() could return any int, including those that cannot be represented as a float.

gcc should be smart enough to know when int literals can be represented precisely:

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 should spit out a warning for initializing h only.

Incidentally, if RAND_MAX is less than or equal to (1<<FLT_MANT_DIG) - 1, you can safely assign rand() to a float, even if the compiler complains to you.

0

精彩评论

暂无评论...
验证码 换一张
取 消