un déréférencement de type punned pointeur de la pause-strict-aliasing règles
J'ai un unsigned char pointeur qui contient une structure.Maintenant, je veux faire ce qui suit
unsigned char buffer[24];
//code to fill the buffer with the relevant information.
int len = ntohs((record_t*)buffer->len);
où record_t structure contient un champ appelé len.Je ne suis pas en mesure de le faire et j'obtiens l'erreur.
error: request for member ‘len’ in something not a structure or union.
Ensuite, j'ai essayé:
int len = ntohs(((record_t*)buffer)->len);
de façon à obtenir la priorité de l'opérateur droite. Qui m'a donné le warning:
.
dereferencing type-punned pointer will break strict-aliasing rules
puis j'ai déclaré
record_t *rec = null;
rec = (record_t*)
ce que je fais mal?
Quelles sont vos options de compilateur? Aussi, se concentrer sur le problème à portée de main, et ne nous renseignent pas sur les précédentes erreurs de syntaxe que vous rencontrez.
En C, c'est
Double Possible de Quelle est la stricte aliasing règle?
En C, c'est
NULL
, pas null
.Double Possible de Quelle est la stricte aliasing règle?
OriginalL'auteur liv2hak | 2011-10-03
Vous devez vous connecter pour publier un commentaire.
Selon le C et le C++ normes, il est comportement indéfini pour accéder à une variable d'un type donné, par l'intermédiaire d'un pointeur vers un autre type. Exemple:
Ici #2 provoque un comportement indéterminé. L'affectation à #1 est appelé "type beaucoup les jeux de mots". Le terme "aliasing" renvoie à l'idée que les différentes variables de pointeur peut pointer à les mêmes données, dans ce cas,
p
alias les donnéesa
. Juridique de l'aliasing est un problème d'optimisation (qui est l'une des principales raisons pour Fortran performances supérieures dans certaines situations), mais ce que nous avons ici est flat-out illégale aliasing.Votre situation n'est pas différente; vous êtes l'accès aux données à
buffer
par l'intermédiaire d'un pointeur vers un type différent (c'est à dire un pointeur qui n'est paschar *
). Ce est tout simplement pas permis.Le résultat est: Vous ne devriez jamais avoir eu de données à
buffer
en premier lieu.Mais comment le résoudre? Assurez-vous d'avoir un pointeur valide! Il y a une exception de type beaucoup les jeux de mots, à savoir l'accès aux données à l'aide d'un pointeur de char, qui est permis. Nous pouvons donc écrire ceci:
La différence essentielle est que nous stockons les données réelles dans une variable de type correct, et seulement après avoir attribué à cette variable peut-on traiter la variable comme un tableau de caractères (ce qui est permis). La morale ici, c'est que le tableau de caractères vient toujours en second, et le type de données real vient en premier.
Non, non, vous êtes exagerating et manque le point. L'accès à un objet par un autre type être un comportement indéfini, si cela est le résultat de l'e.g dans un piège de la représentation ou de défaut d'alignement, mais elle ne doit pas nécessairement. Le point de l'aliasing est complètement différent. C'est parce que la norme permet au compilateur de supposer que les pointeurs de type différent ne sera pas alias les uns des autres et qu'il peut donc effectuer plus agressif optimisations qui peuvent mal se passer si dans reallity ces pointent vers le même objet.
Je ne pense pas que l'alignement joue un rôle dans les règles. Vous pouvez lancer en arrière et en avant, c'est OK (comme
T * p = &x; S * q = (S*)p; T * r = (T*)q; T y = *r;
), mais sinon, c'est juste un comportement indéterminé (qui peut se comporter comme prévu). Aliasing est un concept plus large (par exemple, considérer le "vecteur adder"add(float * a, float * b, float * c)
où il est utile de savoir sia
oub
aliasc
), mais la "stricte aliasing règle" dit que les pointeurs de types différents ne peut jamais alias l'un de l'autre.OriginalL'auteur Kerrek SB
Vous obtenez cet avertissement parce que vous êtes à la rupture strict-aliasing par le fait d'avoir deux pointeurs de types différents pointant vers le même emplacement.
Un moyen de contourner ce qui est d'utiliser des syndicats:
EDIT:
Strictement parlant, ce n'est pas beaucoup plus sûr que votre code d'origine, mais il ne viole pas les strict-aliasing.
SB: Pouvez-vous expliquer ce que vous entendez par "out-of-order"? Oui, je sais que l'approche de l'union est également défini, mais c'est le cas avec le code d'origine.
Il est seulement autorisé à lire le même membre de l'union qui, en dernier écrit à. La lecture d'un autre membre serait presque certainement nécessaire pour votre solution. Il n'y a aucun moyen de belette autour de type non valide beaucoup les jeux de mots; - vous vraiment pour commencer avec une variable de type approprié (voir ma réponse).
il devrait probablement être: int len = ah(record_part.len);
C99 TC3 fait-il légal pour effectuer de type beaucoup les jeux de mots avec les syndicats. (Je ne peux pas citer, mais vérifier stackoverflow.com/questions/7411233/... pour certaines personnes qui sont d'accord avec moi.)
OriginalL'auteur Mysticial
Vous pouvez essayer ceci:
void *
sont inutiles). La bonne façon de réinterpréter les données d'un type de données d'un autre type de copie de données entre les objets en utilisantmemcpy
(au lieu de pointeur direct à base de réinterprétation ou de l'union réinterprétation).Je suis d'accord que cela est correct (et je lui ai donné un +1), mais il serait préférable de ne jamais utiliser
unsigned char[]
pour commencer avec, et de lire les données directement dans une variable du type de droit.OriginalL'auteur Jim Rhodes
Vous avez probablement un avertissement de niveau de jeu qui inclut le strict aliasing mises en garde (il a utilisé pour ne pas être en défaut, mais à un point gcc a retourné la valeur par défaut). essayez
-Wno-strict-aliasing
ou-fno-strict-aliasing
-- ccg devrait pas générer les mises en gardeUne assez bonne explication (basé sur le premier coup d'œil) est Quelle est la stricte aliasing règle?
Je suis demandais si à -1. Donner OP conseils sur la façon de désactiver les avertissements de dangereux UB et ajouter des options pour le code avec UB travail "comme prévu" semble non constructive. Surtout depuis que le code a également d'autres UB en raison de alignement les questions qui ne sont pas pris et ne sera pas résolu par les options. Il se fera un plaisir de travail sur les architectures x86 et puis crash plus tard sur les autres architectures...
Il existe de nombreuses expressions idiomatiques qui sont explicitement l'utilisation de ce comportement (en particulier dans le code de mise en réseau), et pour un long temps de gcc désactivé l'avertissement par défaut spécifiquement, de sorte que la mise en réseau de code ne serait pas le rendement d'un tas de mises en garde 🙂 étant Donné que nous parlons de code de mise en réseau (pris en charge en fonction de la
ntohs
appel), il fait sens pour au moins mentionner ce fait.Comme je l'ai souligné, ce code est presque sûrement pas pour des raisons de gcc ne peut pas contourner: le mauvais alignement. Lecture dans un char tampon puis en essayant d'interpréter la mémoire tampon d'un autre type est juste fondamentalement mauvais, et il montre que l'auteur du code ne comprends pas comment passer un vide pointeur vers l'objet du bon type de
read
/recv
(ou, dans le cas de la plus grande mise en mémoire tampon, comment utilisermemcpy
...)+1 parce que vous donnez un lien expliquant ce qui se passe
OriginalL'auteur Foo Bah