Ce code viole la stricte aliasing règles qui rend illégal le fait d'accéder à un objet par l'intermédiaire d'un pointeur de type différent, bien que l'accès par le biais d'un char * est autorisé. Le compilateur est permis de supposer que les pointeurs de types différents ne désignent pas la même mémoire et d'optimiser en conséquence. Cela signifie également que le code appelle un comportement indéfini , et peut vraiment faire n'importe quoi.
L'une des meilleures références pour cette rubrique est la Compréhension Stricte Aliasing et nous pouvons voir le premier exemple est dans la même veine que celui des OP code:
uint32_t swap_words( uint32_t arg )
{
uint16_t* const sp = (uint16_t*)&arg;
uint16_t hi = sp[0];
uint16_t lo = sp[1];
sp[1] = hi;
sp[0] = lo;
return (arg);
}
L'article explique ce code viole stricte aliasing règles depuis sp
est un alias de arg
, mais ils ont des types différents et dit que, bien que de compiler, il est probable arg
sera inchangée après l' swap_words
de rendement. Bien qu'avec de simples tests, je suis incapable de reproduire ce résultat avec le code ci-dessus, ni l'OPs code mais qui ne veut rien dire puisque c'est un comportement indéfini et donc pas prévisible.
L'article continue à parler de nombreux cas différents et présente plusieurs solution de travail, y compris de type beaucoup les jeux de mots par l'intermédiaire d'un syndicat, ce qui est bien définie dans C991 et peut-être pas définie en C++ , mais dans la pratique, est pris en charge par la plupart des compilateurs, par exemple, ici, est de gcc référence de type beaucoup les jeux de mots. Le thread précédent Objectif de Syndicats en C et C++ va dans les détails sanglants. Bien qu'il existe de nombreux fils sur ce sujet, ce qui semble faire le meilleur travail.
Le code pour que la solution est comme suit:
typedef union
{
uint32_t u32;
uint16_t u16[2];
} U32;
uint32_t swap_words( uint32_t arg )
{
U32 in;
uint16_t lo;
uint16_t hi;
in.u32 = arg;
hi = in.u16[0];
lo = in.u16[1];
in.u16[0] = lo;
in.u16[1] = hi;
return (in.u32);
}
Pour référence la section pertinente de la C99 projet de norme sur le strict aliasing est - 6.5
Expressions paragraphe 7 , qui dit:
Un objet doit avoir sa valeur stockée et accessible uniquement par une lvalue expression qui est l'un des types suivants:76)
- un type compatible avec l'efficacité du type de l'objet,
- une version qualifiée d'un type compatible avec l'efficacité du type de l'objet,
- un type qui est signé ou non signé de type correspondant à l'effectif type de la
objet,
- un type qui est signé ou non signé de type correspondant à une version qualifiée de l'
efficace type de l'objet,
- une agrégation ou une union de type qui comprend l'un des types mentionnés ci-dessus parmi ses
les membres (y compris, de manière récursive, un membre d'un subaggregate ou contenus de l'union), ou
- un type de caractère.
et la note de bas de page 76 dit:
Le but de cette liste est de préciser les circonstances dans lesquelles un objet peut ou peut ne pas être un alias.
et la section pertinente du C++ avant-projet de norme est - 3.10
Lvalues et rvalues paragraphe 10
L'article de Type beaucoup les jeux de mots et strict-aliasing donne un plus doux mais moins complète introduction du sujet et C99 revisitée propose une analyse profonde de C99 et de l'aliasing et n'est pas la lumière de la lecture. Cette réponse à l'Accès inactif membre de l'union indéfinis? va sur les fonds vaseux des détails de la beaucoup les jeux de mots par l'intermédiaire d'un syndicat en C++ et n'est pas la lumière d'une lecture.
Notes de bas de page:
- Citant le commentaire de Pascal Cuoq: [...]C99 qui a d'abord été maladroitement formulée, apparaissant à faire de type beaucoup les jeux de mots par le biais des syndicats indéfini. En réalité, type beaucoup les jeux de mots bien que les syndicats est légal en C89, juridique en C11, et c'était légal en C99 tout le long bien qu'il a fallu attendre 2004 pour le comité de corriger la formulation incorrecte, et la libération subséquente de TC3. open-std.org/jtc1/sc22/wg14/www/docs/dr_283.htm