¿Por qué en C ++ difieren static_cast <unsigned> de números negativos si el número es constante o no?

28

¿Cuáles son las reglas de C ++ que significan que igual es falso ? Dado:

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

Por ejemplo, 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 el siguiente resultado:

 f=ffffffff
cf=0
GreyMattR
fuente
66
Obtenga un voto positivo: ¡ha sido atrapado por una regla olvidada a menudo sobre el comportamiento indefinido!
Betsabé el
¿Qué resultados esperas convertir un flotador negativo en un sin signo?
Amadeus
1
@Amadeus probablemente sea el ajuste habitual que obtenemos al convertir un entero negativo. Tuve que comprobar que era UB porque eso me sorprendió.
Programador
1
@Amadeus, fue más un caso de entender la diferencia. Arreglé un error tipográfico hace unas semanas ... un const-float fue lanzado explícitamente a unsigned (el error), e implícitamente regresó a firmado (como un parámetro de función firmado). Más tarde reflexioné sobre por qué el error original estaba causando un valor cero en la función. Las pruebas sugieren que fue porque el flotador era constante. Un flotador sin constante que fue lanzado explícitamente a sin firmar y luego implícitamente devuelto a firmado no resultó en el mismo comportamiento: el no const de dos lanzamientos tenía el valor original y esperado.
GreyMattR

Respuestas:

26

El comportamiento de su programa no está definido : el estándar C ++ no define la conversión de un tipo de coma flotante negativa a un unsignedtipo.

(Tenga en cuenta que el comportamiento envolvente familiar solo se aplica a los tipos integrales negativos ).

Por lo tanto, no tiene mucho sentido intentar explicar la salida de su programa.

Betsabé
fuente
1
¿Se define si convertiría float-> int-> unsigned en su lugar?
Yksisarvinen
55
@Yksisarvinen: solo si floatestá dentro del rango de un int.
Betsabé el
Acepto que UB es la respuesta correcta, y así debería ser el final ... pero dado que ... ¿Cuál es la respuesta probable del compilador-escritor que explica por qué todos los compiladores en Compiler Explorer (clang / gcc / djgpp) producen la salida equivalente (UB)?
GreyMattR
55
@GreyMattR Si el compilador puede probar que se garantiza que el valor es negativo en el momento del lanzamiento, entonces puede dejar el resultado del lanzamiento sin inicializar, o ponerlo a cero, o cualquier otra cosa que quiera hacer. Si el compilador no puede probar eso, tiene que generar código para realizar el lanzamiento. Para tales propósitos, puede reutilizar el código para emitir al tipo entero con signo (el resultado solo será "incorrecto" si el elenco es UB, lo que significa que en realidad no es incorrecto). Con una optimización más agresiva, el lanzamiento tampoco se emitirá en el caso no constante.
Brian
@Brian, gracias por esa útil explicación.
GreyMattR