2011-10-12 15 views
9

GCC mi avverte che il seguente pezzo di codice contiene una conversione implicita che può modificare il valore di:Perché GCC mette in guardia contro questa conversione implicita?

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

Tuttavia, il seguente non cede alcun avvertimento:

float square = 100; 

l'avvertimento dato da GCC è la seguente:

tests/ChemTests.cpp:17:23: error: conversion to ‘float’ from ‘int’ may alter its value 

non capisco il motivo per cui il primo sarebbe dare un avvertimento, dal momento che è rand() p dichiarato correttamente e restituisce un valore int, proprio come il valore letterale intero di 100.

Perché la prima riga fornisce un avviso al compilatore ma non il secondo, anche se entrambi hanno una conversione implicita da int a float?

+0

Trovo che non ricevo l'avviso a meno che non utilizzi l'opzione '-Wconversion'. –

risposta

14

GCC emette questo avviso quando una perdita di precisione può risultare dal cast. (in altre parole, il valore può essere "modificato")

Nel primo caso, rand() restituisce un int. Dal momento che non tutti i valori che possono essere memorizzati in un int sono rappresentabili come float, emette questo avviso.

Nel secondo caso, 100 può essere colata modo sicuro ad una float senza alcuna perdita di precisione.

+0

Significa che "float f = 123456789' darà un errore? –

+0

Non sarà un errore, ma dovrebbe dare un avvertimento. Non ho GCC di fronte a me in questo momento, ma l'ho appena testato in Visual Studio e dà un avvertimento: 'avviso C4305: 'inizializzazione': troncamento da 'int' a 'float'' – Mysticial

5

Per aggiungere qualcosa a ciò che Mysticial ha scritto (è corretto): l'implementazione di C utilizza float che sono 32 bits IEEE 754 single precision binary floating-point e int 32 bit. Nel "tuo" int puoi avere 31 bit di numero e 1 bit di segno. In "your" float il mantissa è di 24 bit e c'è un bit di segno. Chiaramente int s che hanno bisogno di più di 24 bit più segno possa essere rappresentato non possono essere convertiti esattamente a "vostra" float. (Uso il "tuo" per rappresentare la "vostra" compilatore, il compilatore che si sta utilizzando. Lo standard C non dice la lunghezza esatta float o int).

Ora, lo rand() può generare qualsiasi numero int, quindi il compilatore deve fornire l'avviso. Lo 100 è un valore letterale numerico noto al momento della compilazione, pertanto il compilatore può verificare staticamente se quel numero è convertibile.

(anche senza spiegare esattamente come funzionano Floating Points, il vostro int è 32 bit e "sostiene" solo numeri interi. Il tuo float è di 32 bit e "sostiene" i numeri in virgola mobile. I numeri indicano chiaramente galleggianti sono più difficili da rappresentare (è necessario salvare da qualche parte dove il punto decimale è), quindi ci deve essere un "prezzo" si paga se entrambi int e float hanno la stessa lunghezza. il prezzo è di precisione.)

per rispondere al commento che hai fatto, il numero massimo che si può rappresentare esattamente in un float che è "contigua" a 0 (in modo che 0 ... numero sono tutti esattamente rappresentabili) sono 16.777.215 (che ha mantissa = 16777215 e exp onent = 0) e 16777216 (che ha mantissa = 1 ed esponente = 24, perché è 1 * 2^24). 16777217 non è rappresentabile esattamente. 16777218 è.

0

Non tutti gli int possono essere rappresentati come float. In particolare, se il numero di bit compreso tra il bit più alto e quello più basso impostato su , definito in <float.h>, non può essere rappresentato con precisione come float. (Lo stesso vale per double e DBL_MANT_DIG - 1.) Il compilatore avverte che esiste una potenziale perdita di precisione poiché la dichiarazione di rand() può restituire qualsiasi , inclusi quelli che non possono essere rappresentati come float.

gcc dovrebbe essere sufficiente per sapere intelligente quando int letterali possono essere rappresentati con precisione:

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 dovrebbe sputare fuori un avvertimento per l'inizializzazione solo h.

Per inciso, se RAND_MAX è inferiore o uguale a (1<<FLT_MANT_DIG) - 1, è possibile assegnare in modo sicuro rand() ad un float, anche se il compilatore si lamenta con voi.

Problemi correlati