Encontré este fragmento de código en un proyecto más grande y realmente me hizo pensar.

float sift_handler(int rs2, int rs4, int rs5);
int result1;


float temp = sift_hander(rs2, rs4, rs5);
result1 = *(int*)&temp;

Según tengo entendido, la dirección del flotante temp se convierte en un puntero int y luego se desreferencia. Cuando compilo este código, recibo una advertencia

warning: dereferencing type-punned pointer will break strict-aliasing rules

¿Cuáles son los beneficios reales de esto contra result1 = temp? ¿También es mejor usar round(), que solo lanzar contenido?

2
Mladia 10 may. 2019 a las 12:43

3 respuestas

La mejor respuesta

¿Cuáles son los beneficios reales de esto contra result1 = temp?

Son operaciones completamente diferentes. result1 = temp convierte el valor de flotante a entero. Si temp es 1.0f, entonces result1 será 1. Si el estilo de redondeo predeterminado (que es simplemente truncamiento) no es satisfactorio, puede usar round() antes de asignarlo a un entero.

*(int*)&temp por otro lado reinterpreta los bits de la variable float y almacena esos bits en la variable entera. 1.0f probablemente dará como resultado un valor entero enorme. Esto se llama type punning .

Como te dice el compilador, hacer esta desreferencia con un puntero de tipo no válido es violación de alias estricto . La forma correcta de hacer este tipo de castigo sería:

memcpy(&result, &temp, sizeof temp);
2
user694733 10 may. 2019 a las 09:58

Solía ser un viejo truco para acceder a la representación de un flotador. Eso significa que no es un reparto y (si UB no lo detecta) dará un resultado diferente, excepto 0 en la implementación común.

Al menos desde C99 y C ++ 11 (no estoy seguro para las versiones anteriores), hacerlo invoca Comportamiento indefinido porque viola la estricta regla de alias. Esa regla se inventó para ayudar al compilador en su optimización al afirmar que solo se podía acceder a una variable a través de su propio tipo o mediante un tipo de carácter. De esa manera, cuando el compilador ha almacenado un flotante en un registro, puede suponer que este flotante no se cambiará por ningún cambio de enteros (explicación muy simplificada).

Pero como solía usarse intensamente en programas antiguos, la mayoría de los compiladores (incluso los más recientes) tienen la opción de ignorar la estricta regla de alias.

Aquí su compilador simplemente le advierte que este código viola la estricta regla de alias y puede causar UB en algunas implementaciones.

TL / DR: el uso de un puntero fundido para acceder a un tipo diferente es un intento de reinterpretar la representación subyacente y es UB en C y C ++. Definitivamente no es lo mismo que un elenco.

2
Serge Ballesta 10 may. 2019 a las 10:08

¿Cuáles son los beneficios reales de esto contra result1 = temp

Hace algo completamente diferente y no convierte el flotante en entero. Así que simplemente no utilice punteros punteros en absoluto, hasta que comprenda bien los punteros, los tipos de datos, su representación en la implementación particular, etc.

0
P__J__ 10 may. 2019 a las 09:51