dans l'excellent blog post Quoi Le programmeur doit connaître le comportement non défini , la section «Règles de type violation» indique: P>
Il s'agit d'un comportement indéfini de jeter un int * à un flotteur * et de la déréférence qu'elle (accédant à "Int" comme s'il s'agissait d'un "flotteur"). C exige que ces sortes de conversions de type se produisent via MEMCY: l'utilisation de la coute de pointeur n'est pas correcte et des résultats de comportement non définis. Les règles pour cela sont assez nuancées et je ne veux pas aller dans les détails ici (il existe une exception pour Char *, les vecteurs ont des propriétés spéciales, des syndicats changent de choses, etc.). P> blockQuote>
J'aimerais comprendre les règles dans leur nuance complète. Où sont-ils dans la spécification C ++ 11? Ou à défaut, la spécification C (C90, C99, C11)? P>
dans la spécification C ++ 11 liée à partir de Cette question de dépassement de pile , N3485, je regarde 5,2.10" Reterpret Cast "mais ne vois pas la langue pour une exception pour Char * ou les syndicats. Donc ce n'est probablement pas le bon endroit. Alors où est le bon endroit? P>
3 Réponses :
La norme C ++ affirme que si un certain comportement n'est pas explicitement décrit à définir, il est implicitement non défini. Étant donné que la norme ne définit pas le comportement de la coulée d'un int * code> à
float * code>, il est implicitement indéfini. P>
Où dit-il que le casting à / à partir d'un char * est défini?
5.2.10 Reinterpret Cast [expr.reinterpret.Cast]> strong> p>
7 Un pointeur d'objet peut être explicitement converti en un pointeur d'objet
d'un type DI FF ERENT. 70 quand une prvalue v de type "pointeur à t1" est
converti en type "pointeur sur cv t2", le résultat est 5.2.9 Cast statique [expr.static.Cast] strong> p>
13 Un privalue de type "pointeur sur cv1 vide" peut être converti en un
privalue de type "pointeur à cv2 t," où T est un type d'objet et CV2
est la même qualification CV que, ou une grande qualification de CV plus grande que, CV1.
La valeur du pointeur NULL est convertie en valeur NULL pointeur de la
Type de destination. Une valeur de pointeur de type à un objet converti en
"Pointeur à cv nul" et retour, éventuellement avec DI FF Erent CV-Quali fi cation,
doit avoir sa valeur d'origine. P>
blockQuote> reterpret_cast code> sur les pointeurs est défini en termes de
static_cast code> sur
vide code> pointeurs p>
static_cast
Les types primitifs (char, int, flotter) sont également considérés comme des types d'objet? Ou est "objet" réservé aux classes / structs? En usage familier, les gens distinguent souvent des types primitifs et des objets.
La section 1.8 semble suggérer que les types primitifs sont en effet des objets.
La règle que vous recherchez est au §3.10 / 10 (en C ++ 11): P>
Si un programme tente d'accéder à la valeur stockée d'un objet à travers une glvalue d'autre que l'un des types suivants le Le comportement n'est pas indiqué: - le type dynamique de l'objet, p>
- une version CV-Quali fi ée du type dynamique de l'objet, P>
- un type similaire (comme défini en 4,4) sur le type dynamique de l'objet, P>
- un type qui est le type signé ou non signé correspondant au type dynamique de l'objet, - un type de type signé ou non signé correspondant à une version CV-Quali fi ée du type dynamique de l'objet, p>
- un type d'agrégat ou d'union comprenant l'un des types susmentionnés parmi ses éléments ou non Membres de données (y compris, de manière récursive, un élément ou un élément de données non statique d'un sous-assemblée ou contenait union), p>
- Un type qui est un type de classe de base (éventuellement qualifié) du type dynamique de l'objet, p>
- un type de caractère ou non signé. p> blockQuote>
Il existe différents types (ou motivations) pour non défini comportement. p>
dans le cas de la création d'un
int * code> à
float * code> puis la déséroférance, il est clair que la norme ne peut pas définir Depuis ce qui pourrait arriver dépendra de l'architecture, et la valeur du
int code>. D'autre part, le paragraphe cité est complètement faux-utilisant
memcpy code> pour faire la conversion est également un comportement non défini, pour en grande partie les mêmes raisons. P>
Une des motivations du comportement non définies est de permettre aux implémentations de le définir, d'une manière qui a du sens Pour l'architecture cible, si em> tel existe. C'est tellement un cas. Un compilateur qui l'oblige intentionnellement à échouer est défectueux. Bien sûr, si nous supposons le complément de 32 bits 2
int code> et 32 bits IEEE
float code>, nous pouvons nous attendre à certaines valeurs de le
int code> pour correspondre à la piégeage NAN, qui provoquera le programme échouer. Cela fait partie de la raison pour laquelle le comportement est indéfini; permettre à de telles choses se produira. Mais si nous sommes familier avec les détails de niveau bas du matériel, il devrait fonctionner em> comme prévu, fourni em> le compilateur peut voir le casting. Si ce n'est pas le cas, ceci est un problème QOI avec le compilateur, etc. Un compilateur doit être évité pour de tels types de travail. P>
comme indiqué ci-dessus, ce cas particulier, et en fait, dans tout cas qui impliquent le type punning (écrit à un membre de une union et la lecture d'un autre, par exemple), pose un problème, auquel la norme n'a pas encore trouvé de suffisance formulation. Le problème se produit car normalement, le compilateur est autorisé à supposer que les pointeurs à différents types (sauf types de caractères) ne pas alias; qu'un
int * code> ne peut jamais pointer vers le même objet qu'un
float * code>. Et prouver que deux pointeurs Impossible d'optimiser l'alias n'est pas important. Un compilateur qui casse le code où le pointeur coulait ou l'union est clairement visible est Il suffit de cassé, même si la norme dit que c'est un comportement indéfini. Un compilateur qui brise le code où tout ce qu'il voit sont deux pointeurs aux types non liés est compréhensible, même dans les cas où le Standard indique que le comportement est bien défini. P>
en utilisant
memcpy code> évite ce problème en utilisant deux différents objets, qui ne pas alias. Il rencontre toujours indéfini comportement parce que mettre le modèle de bits d'un
int code> dans un
float code>, puis accédant au flotteur, n'a pas de défini comportement. (Ou vice-versa; Je connais d'au moins une machine où Copier les bits d'un
float code> dans un
int code> peut entraîner une Illégal
int code> valeur.) p>
Merci beaucoup! En ce qui concerne MemCPY, section 3.9 Par 2 dit "Pour tout objet (autre qu'un sous-box de classe de base) de type T de manière triviale t, que l'objet contienne ou non une valeur valide de type T, les octets sous-jacents (1.7) constituent l'objet. peut être copié dans un tableau de char ou non signé. "
@ Marc.martin oui. Les types de caractères sont spéciaux et ni les caractère code> ni
non signé Char code> sont autorisés à avoir des valeurs de piégeage. De même, lorsque le compilateur voit un
char * code>, il doit supposer que le pointeur peut alias tout autre type.
Je n'ai jamais vu une machine qui avait des valeurs illégales int code>, lequel était-ce?
En C ++, vous devez examiner les différents types de mises dans les sections standard 5.4, des pointeurs dérivés en toute sécurité 3.7.4.3, static_cast 5.2.9, réinterpret_cast 5.2.10 ...
Serendipity: Dernière STL d'hier vidéo sur le canal 9 contient un segment sur les moules C ++ (y compris les références à la norme)