¿Es el juego de palabras de tipo a través de una unión no especificado en C99, y se ha especificado en C11?


A number of answers for the Stack Overflow question Getting the IEEE Single-precision bits for a float suggest using a union structure for type punning (e. g.: turning the bits of a float into a uint32_t):

union {
    float f;
    uint32_t u;
} un;
un.f = your_float;
uint32_t target = un.u;

Sin embargo, el valor del uint32_t miembro de la unión parece no estar especificado de acuerdo con la norma C99 (al menos el borrador n1124), donde la sección 6.2.6.1.7 dice:

Cuando un valor se almacena en un miembro de un objeto de tipo union, los bytes de la representación del objeto que no corresponde a ese miembro pero sí a otros miembros toman valores no especificados.

Al menos una nota al pie del proyecto C11 n1570 parece dar a entender que ya no es así (véase la nota 95 en 6.5.2.3):

Si el miembro utilizado para leer el contenido de un objeto union no es el mismo que el miembro utilizado por última vez para almacenar un valor en el objeto, la parte apropiada de la representación del objeto del valor es reinterpretar como una representación de objeto en el nuevo tipo como se describe en 6.2.6 (un proceso a veces llamado " tipo punning"). Esto podría ser una representación trampa.

Sin embargo, el texto de la sección 6.2.6.1.7 es el mismo en el proyecto C99 que en el proyecto C11.

¿Es este comportamiento realmente no especificado bajo C99? ¿Se ha especificado en C11? Me doy cuenta de que la mayoría de los compiladores parecen soportar esto, pero sería bueno saber si está especificado en el estándar, o extensión muy común.

Author: Community, 2012-07-25

4 answers

El comportamiento del juego de palabras tipo con unión cambió de C89 a C99. El comportamiento en C99 es el mismo que en C11.

Como Wug señaló en su respuesta, el juego de palabras de tipo está permitido en C99 / C11. Un valor no especificado que podría ser una trampa se lee cuando los miembros del sindicato son de diferente tamaño.

La nota al pie se agregó en C99 después del Informe de defectos de Clive D. W. Feather #257:

Finalmente, uno de los cambios de C90 a C99 fue eliminar cualquier restricción sobre acceder a un miembro de un sindicato cuando la última tienda fue a una diferente. La razón era que el comportamiento dependería entonces de las representaciones de los valores. Dado que este punto a menudo se malinterpreta, bien podría valer la pena dejarlo claro en el Estándar.

[...]

Para abordar el problema sobre "tipo de juego de palabras", adjunte una nueva nota 78a a las palabras "miembro nombrado" en 6.5.2.3#3: 78a Si el miembro utilizado para acceder al contenido de un objeto union no es el al igual que el miembro utilizado por última vez para almacenar un valor en el objeto, la parte apropiada de la representación del objeto del valor se reinterpreta como una representación de objeto en el nuevo tipo como se describe en 6.2.6 (un proceso a veces llamado "tipo de punning"). Esto podría ser una representación trampa.

La redacción de Clive D. W. Feather fue aceptada para una Corrección Técnica en la respuesta del Comité C para Informe de Defectos #283.

 37
Author: ouah,
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:57

La especificación original de C99 dejó esto sin especificar.

Una de las correcciones técnicas a C99 (TR2, creo) añadió la nota 82 para corregir esta omisión:

Si el miembro utilizado para acceder al contenido de un objeto union no es el mismo que el miembro utilizado por última vez para almacenar un valor en el objeto, la parte apropiada de la representación del objeto del valor se reinterpreta como una representación de objeto en el nuevo tipo como se describe en 6.2.6 (un proceso "tipo de juego"). Esto podría ser una representación trampa.

Esa nota al pie se mantiene en el estándar C11 (es la nota al pie 95 en C11).

 17
Author: Stephen Canon,
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
2012-07-24 22:46:16

Esto siempre ha sido "dudoso". Como otros han señalado, se añadió una nota de pie de página al documento C99 mediante un Corr. Dice lo siguiente:

Si el miembro utilizado para acceder al contenido de un objeto union no es el mismo que el miembro utilizado por última vez para almacenar un valor en el objeto, la parte apropiada de la representación del objeto del valor se reinterpreta como una representación de objeto en el nuevo tipo como se describe en 6.2.6 (un proceso a veces llamado "tipo punning"). Esto podría ser una trampa representatividad.

Sin embargo, las notas al pie se especifican en el Prólogo como no normativas:

Los anexos D y F forman parte normativa de esta norma; los anexos A, B, C, E, G, H, I, J, la bibliografía y el índice son únicamente informativos. De acuerdo con la Parte 3 de las Directivas ISO/IEC, este prólogo, la introducción, las notas, las notas al pie y los ejemplos también son solo para información.

Es decir, las notas al pie no pueden proscribir el comportamiento; sólo debe aclarar el texto existente. Es una opinión impopular, pero la nota a pie de página citada anteriormente en realidad falla en este sentido - no hay tal comportamiento proscrito en el texto normativo. De hecho, hay partes como 6.7.2.1:

... El valor de como máximo uno de los miembros puede almacenarse en un objeto union en cualquier momento

En relación con 6.5.2.3 (en relación con el acceso a los miembros del sindicato con el "."operador):

El valor es el del nombre miembro

Es decir, si el valor de un solo miembro puede ser almacenado, el valor de otro miembro es inexistente. Esto implica fuertemente que el juego de tipo a través de una unión debería no ser posible; el acceso del miembro produce un valor inexistente. El mismo texto todavía existe en el documento C11.

Sin embargo, está claro que el propósito de agregar la nota al pie era permitir el juego de palabras; es solo que el comité aparentemente rompió las reglas sobre las notas al pie que no contienen normas texto. Para aceptar la nota al pie, realmente tienes que ignorar la sección que dice que las notas al pie no son normativas, o tratar de averiguar cómo interpretar el texto normativo de tal manera que apoye la conclusión de la nota al pie (lo que he intentado, y fallé, hacer).

La sección que cita:

Cuando un valor se almacena en un miembro de un objeto de tipo union, los bytes de la representación del objeto que no corresponden a ese miembro pero sí a otro los miembros toman valores no especificados.

... tiene que ser leído cuidadosamente, sin embargo. "Los bytes de la representación del objeto que no corresponden a ese miembro" se refiere a bytes más allá del tamaño del miembro, lo cual no es en sí mismo un problema para el juego de tipo (excepto que no se puede asumir que escribir a un miembro de la unión dejará intacta la parte "extra" de cualquier miembro más grande).

 4
Author: davmac,
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
2016-04-20 12:28:48

Sin embargo, esto parece violar el estándar C99 (al menos el borrador n1124), donde la sección 6.2.6.1.7 establece algunas cosas. ¿Es este comportamiento realmente no especificado bajo C99?

No, estás bien.

Cuando un valor se almacena en un miembro de un objeto de tipo union, los bytes de la representación del objeto que no corresponden a ese miembro pero sí a otros miembros toman valores no especificados.

Esto se aplica a bloques de datos de diferentes Tamaño. Es decir, si usted tiene:

union u
{
    float f;
    double d;
};

Y asignar algo a f, cambiaría los 4 bytes inferiores de d, pero los 4 bytes superiores estarían en un estado indeterminado.

Las uniones existen principalmente para el juego de palabras tipo.

 -1
Author: Wug,
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
2012-07-24 22:41:55