c++ - La advertencia de "desreferenciación de puntero con tipo de letra infringirá las reglas estrictas de aliasing"
warnings strict-aliasing (5)
Utilizo un código donde lanzo un enum * a int *. Algo como esto:
enum foo { ... }
...
foo foobar;
int *pi = reinterpret_cast<int*>(&foobar);
Al compilar el código (g ++ 4.1.2), aparece el siguiente mensaje de advertencia:
dereferencing type-punned pointer will break strict-aliasing rules
Busqué en Google este mensaje y descubrí que ocurre solo cuando está activada la optimización de alias estricta. Tengo las siguientes preguntas:
- Si dejo el código con esta advertencia, ¿generará un código potencialmente incorrecto?
- ¿Hay alguna manera de evitar este problema?
- Si no lo hay, ¿es posible desactivar el alias estricto desde dentro del archivo de origen (porque no quiero desactivarlo para todos los archivos de origen y no quiero hacer una regla de Makefile separada para este archivo de origen)? )?
Y sí, realmente necesito este tipo de aliasing.
¿Has mirado en esta respuesta ?
La regla de alias estricta hace que esta configuración sea ilegal, dos tipos no relacionados no pueden apuntar a la misma memoria. Sólo char * tiene este privilegio . Desafortunadamente, aún puede codificar de esta manera, tal vez obtenga algunas advertencias, pero compile bien.
El alias estricto es una opción del compilador, por lo que debe desactivarlo desde el archivo make.
Y sí, puede generar código incorrecto. El compilador asumirá efectivamente que foobar
y pi
no están unidos, y asumirá que *pi
no cambiará si cambia foobar
.
Como ya se mencionó, use static_cast
en static_cast
lugar (y no punteros).
En orden:
Sí. GCC asumirá que los punteros no pueden alias. Por ejemplo, si asigna a través de uno y luego lee del otro, GCC puede, como optimización, reordenar la lectura y la escritura. He visto que esto sucede en el código de producción, y no es agradable depurarlo.
Varios. Podría usar una unión para representar la memoria que necesita reinterpretar. Podrías usar un
reinterpret_cast
. Puede emitir a través dechar *
en el punto donde reinterpreta la memoria -char *
se define como ser capaz de alias cualquier cosa. Podría usar un tipo que tenga__attribute__((__may_alias__))
. Puede desactivar las suposiciones de alias globalmente usando -fno-strict-aliasing.__attribute__((__may_alias__))
en los tipos utilizados es probablemente lo más cerca que puede estar de deshabilitar la suposición para una sección particular del código.
Para su ejemplo particular, tenga en cuenta que el tamaño de una enumeración está mal definido; GCC generalmente utiliza el tamaño de entero más pequeño que se puede usar para representarlo, por lo que reinterpretar un puntero a una enumeración como un entero podría dejarlo con bytes de datos no inicializados en el entero resultante. No hagas eso ¿Por qué no simplemente convertir a un tipo entero adecuadamente grande?
Pero ¿por qué haces esto? Se romperá si sizeof (foo)! = Sizeof (int). El hecho de que una enumeración sea como un entero no significa que se almacene como uno solo.
Entonces sí, podría generar código "potencialmente" incorrecto.
Puedes usar el siguiente código para emitir tus datos:
template<typename T, typename F>
struct alias_cast_t
{
union
{
F raw;
T data;
};
};
template<typename T, typename F>
T alias_cast(F raw_data)
{
alias_cast_t<T, F> ac;
ac.raw = raw_data;
return ac.data;
}
Ejemplo de uso:
unsigned int data = alias_cast<unsigned int>(raw_ptr);