Warum unterscheidet sich static_cast <unsigned> von negativen Zahlen in C ++, wenn die Zahl konstant ist oder nicht?

28

Was ist die C ++ Regeln, die Mittel gleich ist falsch ?. Gegeben:

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

ZB 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;
}

Erzeugt die folgende Ausgabe:

 f=ffffffff
cf=0
GreyMattR
quelle
6
Haben Sie eine positive Bewertung: Sie wurden von einer oft vergessenen Regel über undefiniertes Verhalten erfasst!
Bathseba
Welche Ergebnisse erwarten Sie, wenn Sie einen negativen Float in einen vorzeichenlosen umwandeln?
Amadeus
1
@Amadeus wahrscheinlich die übliche Umhüllung, die wir beim Konvertieren einer negativen Ganzzahl erhalten. Ich musste überprüfen, ob es UB war, weil mich das überraschte.
AProgrammer
1
@ Amadeus, es ging eher darum, den Unterschied zu verstehen. Ich habe vor ein paar Wochen einen Tippfehler behoben ... ein const-float wurde explizit in unsigned (der Fehler) und implizit zurück in signiert (als signierter Funktionsparameter) umgewandelt. Ich dachte später darüber nach, warum der ursprüngliche Fehler einen Nullwert in der Funktion verursachte. Tests deuten darauf hin, dass der Schwimmer konstant war. Ein Nicht-Konstanten-Float, der explizit in vorzeichenlos umgewandelt und dann implizit in signiert zurückgesetzt wurde, führte nicht zu demselben Verhalten - der zweimal gegossene Nicht-Konstante hatte den ursprünglichen und erwarteten Wert.
GreyMattR

Antworten:

26

Das Verhalten Ihres Programms ist undefiniert : Der C ++ - Standard definiert nicht die Konvertierung eines negativen Gleitkommatyps in einen unsignedTyp.

(Beachten Sie, dass das bekannte Wrap-Around-Verhalten nur für negative Integraltypen gilt .)

Daher macht es wenig Sinn, zu versuchen, Ihre Programmausgabe zu erklären.

Bathseba
quelle
1
Ist definiert, ob ich stattdessen float-> int-> unsigned konvertieren würde?
Yksisarvinen
5
@ Yksisarvinen: Nur wenn das floatim Bereich von a liegt int.
Bathseba
Ich akzeptiere, dass UB die richtige Antwort ist und auch das Ende sein sollte ... aber angesichts dessen ... Was ist die wahrscheinliche Antwort des Compiler-Writers, die erklärt, warum alle Compiler im Compiler Explorer (clang / gcc / djgpp) produzieren die äquivalente (UB) Ausgabe?
GreyMattR
5
@GreyMattR Wenn der Compiler nachweisen kann, dass der Wert zum Zeitpunkt der Umwandlung garantiert negativ ist, kann er das Ergebnis der Umwandlung nicht initialisieren oder auf Null setzen oder was auch immer er sonst tun möchte. Wenn der Compiler dies nicht beweisen kann, muss er Code generieren, um die Umwandlung durchzuführen. Für solche Zwecke kann der Code für die Umwandlung in einen vorzeichenbehafteten Ganzzahltyp wiederverwendet werden (das Ergebnis ist nur dann "falsch", wenn die Umwandlung UB ist, was bedeutet, dass es nicht wirklich falsch ist). Bei einer aggressiveren Optimierung wird der Cast auch im nicht konstanten Fall nicht ausgegeben.
Brian
@ Brian, danke für diese hilfreiche Erklärung.
GreyMattR