Strict Pointer Aliasing: ¿El acceso a través de un puntero/referencia 'volátil' es una solución?
-
24-10-2019 - |
Pregunta
En los talones de un problema específico, una respuesta y comenta a su cuenta, me gustaría entender si es una solución adecuada, solución/hack o simplemente incorrecta.
Específicamente, reescribí código:
T x = ...;
if (*reinterpret_cast <int*> (&x) == 0)
...
Como:
T x = ...;
if (*reinterpret_cast <volatile int*> (&x) == 0)
...
con un volatile
Calificador para el puntero.
Supongamos que tratar T
como int
en mi situación tiene sentido. ¿Acceda esto a través de un volatile
¿Resolver un problema de alias de puntero?
Para una referencia, de la especificación:
Nota: Volátil es una pista de la implementación para evitar la optimización agresiva que involucra el objeto porque el valor del objeto podría cambiarse por medios indetectables por una implementación. Ver 1.9 para una semántica detallada. En general, la semántica del volátil está destinada a ser la misma en C ++ que en C. - Nota final
EDITAR:
El código anterior resolvió mi problema al menos en GCC 4.5.
Solución
Volátil no puede ayudarlo a evitar el comportamiento indefinido aquí. Entonces, si funciona para usted con GCC, es suerte.
Supongamos que T es una cápsula. Entonces, la forma correcta de hacer esto es
T x = …;
int i;
memcpy(&i,&x,sizeof i);
if (i==0)
…
¡Ahí! No hay problema de alias estricto y ningún problema de alineación de memoria. GCC incluso maneja MEMCPY como una función intrínseca (no se inserta ninguna llamada de función en este caso).
Otros consejos
Volátil no puede ayudarlo a evitar el comportamiento indefinido aquí.
Bueno, cualquier cosa con respecto volatile
no es claro en el estándar. Principalmente estuve de acuerdo con su respuesta, pero ahora me gustaría estar un poco en desacuerdo.
Para entender que volatile
significa que el estándar no está claro para la mayoría de las personas, especialmente algunos escritores de compiladores. Es mejor pensar:cuando usas volatile
(y solo cuando), C/C ++ es un ensamblaje de alto nivel.
Al escribir a un volatile
lvalue, el compilador emitirá una tienda o una tienda múltiple si uno no es suficiente (volatile
no implica atómico).
Al escribir a un volatile
Lvalue, el compilador emitirá una carga o una carga múltiple si uno no es suficiente.
Por supuesto, donde no hay una carga o tienda explícita, el compilador solo emitirá instrucciones que implican una carga o tienda.
Sellibitze dio la mejor solución: usar memcpy
Para reinterpretaciones de bits.
Pero si todos los accesos a una región de memoria se realizan con volatile
Lvalues, Está perfectamente claro que las estrictas reglas de alias no se aplican. Esta es la respuesta a su pregunta.