Sur gcc-strict-aliasing-and-casting-through-a-union J'ai demandé si quelqu'un avait rencontré des problèmes avec le contournement des unions par des pointeurs. Jusqu'à présent, la réponse semble être Non .
Cette question est plus large : Avez-vous tout des histoires d'horreur sur gcc et l'aliasing strict ?
Historique : Citation de La réponse d'AndreyT dans c99-strict-aliasing-rules-in-c-gcc :
"Les règles strictes d'aliasing sont enracinées dans des parties de la norme qui étaient présentes en C et C++ depuis le début des temps [normalisés]. La clause qui interdit l'accès à un objet d'un type par une lvalue d'un autre type est présente dans C89/90 (6.3) ainsi que dans C++98 (3.10/15). ... C'est juste que tous les compilateurs n'ont pas voulu (ou osé) l'appliquer ou s'y fier. "
Bien, gcc ose aujourd'hui le faire, avec ses -fstrict-aliasing
l'interrupteur. Et cela a causé quelques problèmes. Voir, par exemple, l'excellent article http://davmac.wordpress.com/2009/10/ sur un bug de Mysql, et la discussion tout aussi excellente dans http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html .
Quelques autres liens moins pertinents :
- performance-impact-of-fno-strict-aliasing
- anticrénelage strict
- when-is-char-safe-for-strict-pointer-aliasing
- comment-detecter-l'aliasing-stricte-au-temps-compilé
Donc, pour répéter, avez-vous une histoire d'horreur à raconter ? Problèmes no indiqué par -Wstrict-aliasing
serait, bien sûr, préférable. Les autres compilateurs C sont également les bienvenus.
Ajouté le 2 juin : Le premier lien dans Réponse de Michael Burr qui fait en effet qualifié d'histoire d'horreur, est peut-être un peu daté (de 2003). J'ai fait un test rapide, mais le problème a apparemment disparu.
Source :
#include <string.h>
struct iw_event { /* dummy! */
int len;
};
char *iwe_stream_add_event(
char *stream, /* Stream of events */
char *ends, /* End of stream */
struct iw_event *iwe, /* Payload */
int event_len) /* Real size of payload */
{
/* Check if it's possible */
if ((stream + event_len) < ends) {
iwe->len = event_len;
memcpy(stream, (char *) iwe, event_len);
stream += event_len;
}
return stream;
}
La plainte spécifique est :
Certains utilisateurs se sont plaints que lorsque le code [ci-dessus] est compilé sans le -fno-strict-aliasing, l'ordre de l'écriture et du memcpy est inversé (ce qui signifie qu'un faux len est mem-copié dans le flux).
Code compilé, utilisant gcc 4.3.4 sur CYGWIN avec -O3 (merci de me corriger si je me trompe - mon assembleur est un peu rouillé !)
_iwe_stream_add_event:
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $20, %esp
movl 8(%ebp), %eax # stream --> %eax
movl 20(%ebp), %edx # event_len --> %edx
leal (%eax,%edx), %ebx # sum --> %ebx
cmpl 12(%ebp), %ebx # compare sum with ends
jae L2
movl 16(%ebp), %ecx # iwe --> %ecx
movl %edx, (%ecx) # event_len --> iwe->len (!!)
movl %edx, 8(%esp) # event_len --> stack
movl %ecx, 4(%esp) # iwe --> stack
movl %eax, (%esp) # stream --> stack
call _memcpy
movl %ebx, %eax # sum --> retval
L2:
addl $20, %esp
popl %ebx
leave
ret
Et pour le deuxième lien dans la réponse de Michael,
*(unsigned short *)&a = 4;
gcc donne généralement (toujours ?) un avertissement. Mais je croire une solution valable à ce problème (pour gcc ) est à utiliser :
#define CAST(type, x) (((union {typeof(x) src; type dst;}*)&(x))->dst)
// ...
CAST(unsigned short, a) = 4;
J'ai demandé à SO si c'était possible dans les cas suivants gcc-strict-aliasing-and-casting-through-a-union mais jusqu'à présent, personne n'est en désaccord.
0 votes
Duplicata possible de gcc, strict-aliasing, et casting à travers une union
0 votes
Réponse du caf stackoverflow.com/questions/1926282/ est une autre référence, mais elle n'est que théorique, pas horrible.
1 votes
En outre, pour être clair, les références à gcc les bogues de codage ne sont pas utiles - tout code a des bogues. Mais design Les "bugs" peuvent être critiqués.
3 votes
Et le commentaire de caf à la réponse d'AndreyT citée est amusant : "Je ne suis toujours pas sûr qu'il soit possible d'utiliser les parties de l'API sockets BSD liées à sockaddr sans enfreindre les règles strictes d'aliasing.
0 votes
John Regehr donne deux exemples intéressants et courts d'incohérences dans GCC et Clang.
0 votes
Une ancienne : gcc.gnu.org/ml/gcc-bugs/2000-03/msg00155.html : Lorsque memcpy() était utilisé, tout allait bien, mais lorsqu'il a été inlined par GCC, il ne gère pas les accès non alignés ... mauvais code.
6 votes
Je pense que le point de vue selon lequel les auteurs de compilateurs étaient trop paresseux pour exploiter la règle est quelque peu révisionniste. Les règles de type en C rendent impossible la création de fonctions qui gèrent et recyclent les blocs de mémoire de manière agnostique. Ainsi, la conformité aux règles de type peut imposer des pénalités massives (50 % ou plus) en termes de temps et d'espace par rapport à ce qui pourrait être réalisé en leur absence. Pour de nombreux types de programmation, il n'y a pas d'optimisations que les règles pourraient permettre qui permettraient de surmonter cette pénalité massive.
1 votes
Quant à l'histoire d'horreur, le fragment de code était en fait OK. Le vrai bug se trouvait dans memcpy. Ils utilisaient un memcpy personnalisé (une macro) qui utilise des longs pour copier des octets. Sinon, il est tout à fait normal de convertir des pointeurs vers des structures en pointeurs vers des caractères, et de les copier avec memcpy.