"dereferencing type-punned pointer will break strict-aliasing rules" advertencia
Utilizo un código donde lanzo una enumeración* a int*. Algo como esto:
enum foo { ... }
...
foo foobar;
int *pi = reinterpret_cast<int*>(&foobar);
Al compilar el código (g++ 4.1.2), recibo el siguiente mensaje de advertencia:
dereferencing type-punned pointer will break strict-aliasing rules
Busqué en Google este mensaje y descubrí que solo sucede cuando la optimización estricta de aliasing está activada. Tengo las siguientes preguntas:
- Si dejo el código con esta advertencia, ¿generará código potencialmente incorrecto?
- ¿Hay alguna manera de solucionar este problema?
- Si no lo hay, ¿es ¿es posible desactivar el alias estricto desde el interior 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 alias.
5 answers
En orden:
Sí. GCC asumirá que los punteros no pueden alias. Por ejemplo, si asigna a través de uno y luego lee desde el otro, GCC puede, como optimización, reordenar la lectura y escritura - he visto que esto sucede en el código de producción, y no es agradable depurar.
Varios. Podrías usar una unión para representar la memoria que necesitas reinterpretar. Podrías usar un
reinterpret_cast
. Puedes lanzar a través dechar *
en el punto donde reinterpretas la memoria -char *
se definen como ser capaz de alias cualquier cosa. Podría usar un tipo que tenga__attribute__((__may_alias__))
. Puede desactivar las suposiciones de aliasing globalmente usando-fno-strict-aliasing.__attribute__((__may_alias__))
en los tipos utilizados es probablemente lo más cercano que puede llegar a deshabilitar la suposición para una sección particular de código.
Para su ejemplo particular, tenga en cuenta que el tamaño de una enumeración está mal definido; GCC generalmente usa el tamaño 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 dejarle con bytes de datos no iniciados en el entero resultante. No hagas eso. ¿Por qué no simplemente convertir a un tipo entero adecuadamente grande?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-16 12:41:36
Pero ¿por qué estás haciendo esto? Se romperá si sizeof (foo) != tamaño de (int). El hecho de que una enumeración sea como un entero no significa que se almacene como uno.
Así que sí, podría generar código "potencialmente" incorrecto.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-12 09:29:30
Puede usar el siguiente código para emitir sus 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);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-06 08:56:50
Has mirado en esta respuesta ?
La regla de alias estricta hace esto configuración ilegal, dos tipos no relacionados no puedo señalar el mismo recuerdo. Únicamente char * tiene este privilegio . Desafortunadamente todavía puedes codificar esto manera, tal vez obtener algunas advertencias, pero tienen se compile bien.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:25:27
El alias estricto es una opción del compilador, por lo que debe desactivarlo desde el makefile.
Y sí, puede generar código incorrecto. El compilador asumirá efectivamente que foobar
y pi
no están enlazados, y asumirá que *pi
no cambiará si foobar
cambia.
Como ya se mencionó, use static_cast
en su lugar (y sin punteros).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-12 09:35:17