Perché in C ++ static_cast <unsigned> di numeri negativi differisce se il numero è costante o no


28

Quali sono le regole C ++ che significa che uguale è falso ? Dato:

float f {-1.0};
bool equal = (static_cast<unsigned>(f) == static_cast<unsigned>(-1.0));

Ad esempio https://godbolt.org/z/fcmx2P

#include <iostream>

int main() 
{
          float   f {-1.0};
    const float  cf {-1.0};

    std::cout << std::hex;
    std::cout << " f" << "=" << static_cast<unsigned>(f) << '\n';
    std::cout << "cf" << "=" << static_cast<unsigned>(cf) << '\n';

    return 0;
}

Produce il seguente output:

 f=ffffffff
cf=0

6
Avere un voto: sei stato catturato da una regola spesso dimenticata sul comportamento indefinito!
Bathsheba,

Quali risultati ti aspetti di convertire un float negativo in un unsigned?
Amadeus,

1
@Amadeus probabilmente il solito giro che otteniamo quando convertiamo un intero negativo. Ho dovuto verificare che fosse UB perché mi ha sorpreso.
Programmatore

1
@Amadeus, era più un caso di capire la differenza. Ho corretto un errore di battitura qualche settimana fa ... un const-float è stato esplicitamente lanciato su unsigned (il bug), e implicitamente di nuovo su firmato (come parametro di funzione firmato). Successivamente ho riflettuto sul perché il bug originale causasse un valore zero nella funzione. I test suggeriscono che era perché il galleggiante era const. Un float non const che è stato esplicitamente cast su unsigned e poi implicitamente cast su sign non ha prodotto lo stesso comportamento: la non const ha due volte il valore originale e previsto.
GreyMattR

Risposte:


26

Il comportamento del programma non è definito : lo standard C ++ non definisce la conversione di un tipo a virgola mobile negativo in un unsignedtipo.

(Nota che il familiare comportamento avvolgente si applica solo ai tipi integrali negativi .)

Quindi, non ha senso cercare di spiegare l'output del tuo programma.


1
È definito se invece convertissi float-> int-> unsigned?
Yksisarvinen,

5
@Yksisarvinen: solo se floatè compreso nell'intervallo di un int.
Bathsheba,

Accetto che UB sia la risposta corretta, e quindi dovrebbe esserne la fine ... ma dato che ... Qual è la probabile risposta di compilatore-scrittore che spiega perché tutti i compilatori su Compiler Explorer (clang / gcc / djgpp) producono l'uscita equivalente (UB)?
GreyMattR

5
@GreyMattR Se il compilatore può dimostrare che il valore è garantito come negativo al momento del cast, può lasciare il risultato del cast non inizializzato o impostarlo su zero o qualsiasi altra cosa voglia fare. Se il compilatore non può dimostrarlo, deve generare codice per eseguire il cast. A tal fine, può riutilizzare il codice da trasmettere al tipo intero con segno (il risultato sarà "sbagliato" solo se il cast è UB, il che significa che non è effettivamente sbagliato). Con un'ottimizzazione più aggressiva, il cast non verrà emesso neanche nel caso non const.
Brian,

@Brian, grazie per questa utile spiegazione.
GreyMattR
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.