Est-ce que la punition de type à travers une union non spécifiée dans C99, et est-elle devenue spécifiée dans C11?

Un certain nombre de réponses à la question Stack Overflow Obtenir les bits IEEE Single-Precision pour un float suggère d’utiliser une structure d’ union pour le type punning (ex.: uint32_t les bits d’un float en uint32_t ):

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

Cependant, la valeur du membre uint32_t de l’union semble être non spécifiée selon la norme C99 (au moins le projet n1124), où la section 6.2.6.1.7 indique:

Lorsqu’une valeur est stockée dans un membre d’un object de type union, les octets de la représentation d’object qui ne correspondent pas à ce membre mais correspondent aux autres membres prennent des valeurs non spécifiées.

Au moins une note de bas de page du projet C11 n1570 semble impliquer que ce n’est plus le cas (voir note 95 au 6.5.2.3):

Si le membre utilisé pour lire le contenu d’un object union n’est pas identique au dernier membre utilisé pour stocker une valeur dans l’object, la partie appropriée de la représentation d’object de la valeur est réinterprétée comme une représentation d’object dans le nouveau type décrit en 6.2.6 (un processus parfois appelé «type punning»). Cela pourrait être une représentation de piège.

Cependant, le texte de la section 6.2.6.1.7 est le même dans le projet C99 que dans le projet C11.

Ce comportement est-il réellement non spécifié sous C99? A-t-il été spécifié dans C11? Je me rends compte que la plupart des compilateurs semblent soutenir cela, mais ce serait bien de savoir si c’est spécifié dans la norme, ou juste une extension très commune.

Le comportement de type punition avec union est passé de C89 à C99. Le comportement en C99 est le même que C11.

Comme Wug a noté dans sa réponse, la punition de type est autorisée dans C99 / C11. Une valeur non spécifiée qui pourrait être un piège est lue lorsque les membres de l’union sont de taille différente.

La note de bas de page a été ajoutée en C99 après le rapport sur le défaut de plume N ° 257 de Clive DW:

Enfin, l’un des changements de C90 à C99 consistait à supprimer toute ressortingction d’access à un membre d’un syndicat lorsque le dernier magasin était à un autre. Le raisonnement était que le comportement dépendrait alors des représentations des valeurs. Étant donné que ce point est souvent mal compris, il pourrait être utile de le préciser dans la norme.

[…]

Pour résoudre le problème de “type punning”, joignez une nouvelle note de bas de page 78a aux mots “membre nommé” dans 6.5.2.3 # 3: 78a Si le membre utilisé pour accéder au contenu d’un object d’union n’est pas le dernier membre utilisée pour stocker une valeur dans l’object, la partie appropriée de la représentation d’object de la valeur est réinterprétée comme une représentation d’object dans le nouveau type, comme décrit au 6.2.6 (processus parfois appelé “type punning”). Cela pourrait être une représentation de piège.

Le libellé de Clive DW Feather a été accepté pour un rectificatif technique dans la réponse par le Comité C pour le rapport de défauts # 283 .

La spécification C99 originale laissait cette précision.

L’un des rectificatifs techniques à C99 (TR2, je pense) a ajouté la note de bas de page 82 pour corriger cet oubli:

Si le membre utilisé pour accéder au contenu d’un object union n’est pas identique au dernier membre utilisé pour stocker une valeur dans l’object, la partie appropriée de la représentation d’object de la valeur est réinterprétée comme une représentation d’object dans le nouveau type décrit en 6.2.6 (un processus parfois appelé “type punning”). Cela pourrait être une représentation de piège.

Cette note de bas de page est conservée dans la norme C11 (note de bas de page 95 en C11).

Cela a toujours été “risqué”. Comme d’autres l’ont noté, une note de bas de page a été ajoutée à C99 via un règlement technique. Il se lit comme suit:

Si le membre utilisé pour accéder au contenu d’un object union n’est pas identique au dernier membre utilisé pour stocker une valeur dans l’object, la partie appropriée de la représentation d’object de la valeur est réinterprétée comme une représentation d’object dans le nouveau type décrit en 6.2.6 (un processus parfois appelé “type punning”). Cela pourrait être une représentation de piège.

Cependant, les notes de bas de page sont spécifiées dans l’avant-propos comme étant non normatives:

Les annexes D et F constituent une partie normative de cette norme; les annexes A, B, C, E, G, H, I, J, la bibliographie et l’index sont fournis à titre d’information uniquement. Conformément à la partie 3 des directives ISO / CEI, cet avant-propos, l’introduction, les notes, les notes de bas de page et les exemples sont également fournis à titre d’information uniquement .

Autrement dit, les notes de bas de page ne peuvent proscrire un comportement; ils devraient seulement clarifier le texte existant. C’est une opinion impopulaire, mais la note de bas de page citée ci-dessus échoue à cet égard – il n’y a pas un tel comportement interdit dans le texte normatif. En effet, il existe des parties telles que 6.7.2.1:

… La valeur d’au plus un des membres peut être stockée dans un object d’union à tout moment

En conjonction avec 6.5.2.3 (concernant l’access aux membres d’union avec l’opérateur “.”):

La valeur est celle du membre nommé

Par exemple, si la valeur d’un seul membre peut être stockée, la valeur d’un autre membre est inexistante. Cela implique fortement que la punition de type via une union ne devrait pas être possible; l’access membre donne une valeur inexistante. Le même texte existe toujours dans le document C11.

Cependant, il est clair que le but de l’ajout de la note de bas de page était de permettre la punition de type; c’est simplement que le comité a apparemment enfreint les règles concernant les notes de bas de page ne contenant pas de texte normatif. Pour accepter la note de bas de page, vous devez vraiment ignorer la section indiquant que les notes de bas de page ne sont pas normatives, ou essayer de comprendre comment interpréter le texte normatif de manière à prendre en charge la conclusion de la note de bas de page échoué, à faire).

La section que vous citez:

Lorsqu’une valeur est stockée dans un membre d’un object de type union, les octets de la représentation d’object qui ne correspondent pas à ce membre mais correspondent aux autres membres prennent des valeurs non spécifiées.

… doit être lu attentivement, cependant. “Les octets de la représentation d’object qui ne correspondent pas à ce membre ” font référence à des octets au-delà de la taille du membre, ce qui n’est pas un problème de type (sauf que vous ne pouvez pas “extra” partie de n’importe quel plus grand membre intact.

Cependant, cela semble enfreindre la norme C99 (au moins le projet n1124), où la section 6.2.6.1.7 indique certaines choses. Ce comportement est-il réellement non spécifié sous C99?

Non, tu vas bien.

Lorsqu’une valeur est stockée dans un membre d’un object de type union, les octets de la représentation d’object qui ne correspondent pas à ce membre mais correspondent aux autres membres prennent des valeurs non spécifiées.

Cela s’applique aux blocs de données de différentes tailles. Ie, si vous avez:

 union u { float f; double d; }; 

et vous affectez quelque chose à f, cela changerait les 4 octets inférieurs de d, mais les 4 octets supérieurs seraient dans un état indéterminé.

Les syndicats existent principalement pour le type punning.