c c99 void-pointers strict-aliasing type-punning

Escriba punning con void*sin romper la regla de alias estricta en C99



void-pointers strict-aliasing (1)

Hace poco me encontré con la estricta regla de alias, pero tengo problemas para entender cómo usar void * para realizar el punteo de tipo sin infringir la regla.

Sé que esto rompe la regla:

int x = 0xDEADBEEF; short *y = (short *)&x; *y = 42; int z = x;

Y sé que puedo usar de forma segura una unión en C99 para la tipificación de tipos:

union{ int x; short y; } data; data.x = 0xDEADBEEF; data.y = 42; int z = data.x;

Pero, ¿cómo uso void * para realizar el punteo de tipo de forma segura en C99? Es correcto lo siguiente:

int x = 0xDEADBEEF; void * helper = (void *)&x; short *y = (short *)helper; *y = 42; int z = x;

Sospecho que el código aún romperá la regla de alias estricta ya que la memoria en la dirección de la variable x se puede modificar tanto con x como con una y referencia.

Si el punteo de tipo no está definido a través de void * , ¿cuál es el propósito del void * en C99?


void * no tiene nada que ver con el tipeado. Sus principales objetivos son:

  1. Para permitir la asignación genérica y las operaciones de liberación que no se preocupan por el tipo de objeto que la persona que llama está almacenando allí (por ejemplo, malloc y free ).

  2. Para permitir que una persona que llama pase un puntero a un tipo arbitrario a través de una función que lo devolverá a través de una devolución de llamada (por ejemplo, qsort y pthread_create ). En este caso, el compilador no puede imponer la verificación de tipos; es su responsabilidad al escribir la persona que llama y la devolución de llamada para asegurarse de que la devolución de llamada acceda al objeto con el tipo correcto.

Los punteros para void también se usan en algunos lugares (como memcpy ) que realmente operan en un objeto como la representación de caracteres unsigned char [] superpuesta para el objeto. Esto podría verse como una tipificación de tipo, pero no es una violación de alias porque los tipos char pueden alias cualquier cosa para acceder a su representación. En este caso, el unsigned char * también funcionaría, pero void * tiene la ventaja de que los punteros se convierten automáticamente en void * .

En su ejemplo, dado que el tipo original es int y no una unión, no existe una forma legal de escribir con letra y acceder a él de manera short . En su lugar, podría copiar el valor de x en una unión, realizar una tipificación de tipos bien definida allí, y luego copiarlo de nuevo. Un buen compilador debe omitir la copia por completo. Alternativamente, podría dividir la escritura en escrituras de caracteres y luego sería un alias legal.