Una pregunta de abogado de idiomas. Hmkay.
Mi top3 personal:
- violar la estricta regla de aliasing
- violar la estricta regla de aliasing
violar la estricta regla de aliasing
:-)
Editar Aquí hay un pequeño ejemplo que lo hace mal dos veces:
(asumir 32 enteros bits y Little Endian)
float funky_float_abs (float a)
{
unsigned int temp = *(unsigned int *)&a;
temp &= 0x7fffffff;
return *(float *)&temp;
}
Ese código intenta obtener el valor absoluto de un flotador a poco, haciendo girar con el signo bit directamente en la representación de un flotador.
Sin embargo, el resultado de crear un puntero a un objeto mediante conversión de un tipo a otro no es válido C. El compilador puede suponer que los punteros a diferentes tipos no apuntan al mismo bloque de memoria. Esto es cierto para todo tipo de punteros excepto void * y char * (sign-ness no importa).
En el caso anterior lo hago dos veces. Una vez para obtener un alias int para el float a, y una vez para convertir el valor a float.
Existen tres formas válidas de hacer lo mismo.
Use un puntero de char o void durante el lanzamiento. Estos siempre se parecen a cualquier cosa, por lo que están seguros.
float funky_float_abs (float a)
{
float temp_float = a;
// valid, because it's a char pointer. These are special.
unsigned char * temp = (unsigned char *)&temp_float;
temp[3] &= 0x7f;
return temp_float;
}
Usar memcopy. Memcpy toma punteros vacíos, por lo que también forzará el aliasing.
float funky_float_abs (float a)
{
int i;
float result;
memcpy (&i, &a, sizeof (int));
i &= 0x7fffffff;
memcpy (&result, &i, sizeof (int));
return result;
}
La tercera manera válida: usar uniones. Este es explícitamente no indefinido desde C99:
float funky_float_abs (float a)
{
union
{
unsigned int i;
float f;
} cast_helper;
cast_helper.f = a;
cast_helper.i &= 0x7fffffff;
return cast_helper.f;
}
'foo (C++, c)' y 'foo (++ c, c)' son ** comportamiento indefinido **, que prevalece por completo sin especificar. –