"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.

Author: Lightness Races in Orbit, 2010-11-12

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 de char * 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?

 55
Author: moonshadow,
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.

 10
Author: CashCow,
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);
 9
Author: Markus Lenger,
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.

 5
Author: icecrime,
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).

 2
Author: Let_Me_Be,
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