Donc, la norme (faisant référence à N1570 < / a>) dit ce qui suit sur la comparaison des pointeurs: P>
C99 6.5.8 / 5 opérateurs relationnels p>
Lorsque deux pointeurs sont comparés, le résultat dépend du relatif.
Emplacements dans l'espace d'adressage des objets pointés vers.
... [Définitions évidentes Snip de comparaison au sein des agrégats] ...
Quelle est la justification de cette instance de UB, par opposition à la conversion (par exemple) à la conversion (par exemple) vers Y a-t-il une architecture de la machine où une commande totale sensible sur des pointeurs est difficile à construire? Existe-t-il une classe d'optimisation ou d'analyse que des comparaisons de pointeur sans restriction entravaient? P>
Une réponse supprimée à Cette question mentionne Que ce morceau de UB permet de sauter une comparaison des registres du segment et de comparer uniquement des compensations. Est-ce particulièrement précieux pour conserver? P>
(cette même réponse supprimée, ainsi que celle ici, notez que, en C ++,
intPTR_T code> et comparaison de cela? P>
std :: moins code> etc. et similaire doivent mettre en œuvre une commande totale sur les pointeurs, si l'opérateur de comparaison normal fait ou non.) p>
4 Réponses :
Divers commentaires de la liste de diffusion d'UB Discussion Justification pour séparément, je pense que la langue principale devrait simplement reconnaître le fait que toutes les machines de nos jours ont un modèle de mémoire plate. P>
blockQuote>
et 2 : P>
Ensuite, nous avons peut-être besoin d'un nouveau type qui garantit une commande totale lorsque
converti d'un pointeur (par exemple dans les architectures segmentées, conversion
nécessiterait de prendre l'adresse du registre du segment et d'ajouter le
offset stocké dans le pointeur). p>
blockQuote>
et 3 : p>
Les pointeurs, tandis que, historiquement non totalement commandé, sont pratiquement si
Pour tous les systèmes existants aujourd'hui, à l'exception de la tour d'ivoire
esprits du comité, donc le point est discutable. p>
blockQuote>
et 4 : P>
Mais, même si des architectures segmentées, il est peu probable que ce soit, vient
retour, le problème de commande doit encore être adressé, comme STD :: Moins
est nécessaire pour commander totalement les pointeurs. Je veux juste que l'opérateur Pourquoi tout le monde devrait-il prétendre souffrir (et que je fais faire semblant de faire semblant,
Parce qu'en dehors d'un petit contingent du comité, les gens déjà
Supposons que les pointeurs sont totalement commandés par rapport à l'opérateur <) à
répondre aux besoins théoriques de certains actuellement inexistants
Architecture? P>
blockQuote>
compteur à la tendance des commentaires de la liste ub Mailing em>, indique que FuZXXL souligne que la prise en charge des DOS est une raison pour ne pas prendre en charge les pointeurs totalement ordonnés. P>
mise à jour b> p>
Ceci est également pris en charge par le Annoté C ++ Manuel de référence ( bras em >) qui dit que cela était dû au fardeau de l'appui sur cela sur des architectures segmentées: p>
L'expression peut ne pas évaluer de faux sur les architectures segmentées
[...] Cela explique pourquoi l'addition, la soustraction et la comparaison de
Les pointeurs sont définis uniquement pour les pointeurs dans un tableau et un élément
Au-delà de la fin. [...] Utilisateurs de machines avec une adresse non croissée
l'espace développé des idiomes, cependant, qui ont évoqué les éléments au-delà
la fin de la matrice [...] n'était pas portable aux architectures segmentées
À moins que des efforts particuliers ne soient déplacés [...], [...] serait coûteux
et servir peu de fins utiles. P>
blockQuote>
Je pense que soutenir DOS est une vaste raison de ne pas mandater des pointeurs totalement ordonnés. Où ces personnes ont-elles l'idée que leurs machines sont les seules machines que les gens écrivent C code?
Certains algorithmes nécessitant une commande totale, mais beaucoup plus nécessitent simplement qu'une comparaison entre deux pointeurs arbitraires n'indiquent aucun effet secondaire autre que cédant zéro ou un. Pouvez-vous penser à une raison saine La norme n'aurait pas dû exiger que des implémentations ne garantissent ni de prédéfinir une macro indiquant qu'ils ne peuvent pas?
Je pense qu'il est indéfini de sorte que c peut être exécuté sur des architectures où, en vigueur, des "pointeurs intelligents" sont implémentés dans du matériel, avec diverses vérifications afin de garantir que les pointeurs ne signent jamais accidentellement à l'extérieur des régions de mémoire sont définies. pour. Je n'ai jamais utilisé personnellement une telle machine, mais la façon de penser à eux est que le calcul d'un pointeur invalide est précisément aussi interdit que de diviser par 0; Vous êtes susceptible d'obtenir une exception d'exécution qui termine votre programme. En outre, qu'est-ce que l'interdit est l'informatique em> le pointeur, vous n'avez même pas à la désirer pour obtenir l'exception. P>
Oui, je pense que la définition a également fini par permettre des comparaisons plus efficaces de registres offset dans le code Old 8086, mais ce n'était pas la seule raison. P>
Oui, un compilateur pour l'une de ces architectures de pointeur protégés pourrait mettre en œuvre théoriquement les comparaisons "interdites" en convertissant à l'équivalent ou à l'équivalent, mais (a), il serait probablement beaucoup moins efficace de le faire et (b) Soyez un contournement volontairement délibéré de la protection prévue de l'architecture, la protection qui au moins certaines des programmeurs C architecture voudraient probablement être activée (non désactivée). P>
Le 8086 est un processeur avec des registres 16 bits et un espace d'adressage 20 bits. Pour faire face au manque de bits dans ses registres, un ensemble de registres segment em> existe. Sur l'accès à la mémoire, l'adresse de la mémoire est calculée comme ceci: Cette comparaison rapide du cours ne fonctionne que lorsque les pointeurs sont dérivés de la même adresse de base, qui est l'une des raisons pour lesquelles la norme C définit les comparaisons du pointeur uniquement pour que les deux pointeurs indiquent dans le même objet. P> Si vous souhaitez une comparaison bien ordonnée pour tous les pointeurs, envisagez de convertir les pointeurs vers address = 16 * segment + register
uintptr_t code> d'abord. p> p>
Historiquement, affirmant que cette action a invoqué un comportement indéfini signifiait que tout programme qui a utilisé de telles actions pourrait être attendu correctement uniquement sur ces mises en œuvre définies, pour cette action, le comportement répondant à leurs exigences EM>. Spécification d'une action invoquée un comportement indéfini ne voulait pas dire que les programmes utilisant de telles mesures devraient être considérés comme «illégitimes», mais devaient plutôt permettre à C d'être utilisé pour exécuter des programmes qui n'avaient pas besoin de telles actions, sur des plates-formes qui ne pouvaient pas efficacement Soutenez-les. En règle générale, l'attente était qu'un compilateur émettrait soit la séquence d'instructions qui exécuteraient plus efficacement l'action indiquée dans les cas requis par la norme, et faire ce que cette séquence d'instructions se produisait dans d'autres cas. ou produirait une séquence d'instructions dont le comportement dans de tels cas a été jugé de manière plus "utile" que la séquence naturelle. Dans les cas où une action peut déclencher un piège au matériel, ou lorsque la déclenchement d'un piège à système d'exploitation pourrait être considérée comme précisée à l'exécution de la séquence d'instructions «naturelle» et lorsqu'un piège pourrait causer des comportements en dehors de la commande du compilateur C, La norme n'impose aucune exigence. Ces cas sont ainsi étiquetés comme "comportement non défini". P> Comme d'autres l'ont noté, il existe certaines plates-formes où Jusqu'à récemment, le fait qu'une action particulière invoquerait le comportement non défini par la norme ne poserait généralement que des difficultés pour Les gens essayant d'écrire du code sur des plates-formes où l'action aurait des conséquences indésirables. En outre, sur des plates-formes où une action ne pouvait avoir des conséquences indésirables que si un compilateur est sorti de sa façon de le faire, il était généralement accepté de pratique pour les programmeurs de s'appuyer sur une telle action se comportant sensiblement. P> si on accepte les notions qui: p> Les auteurs de la norme attendaient que les comparaisons entre des pointeurs non liés fonctionneraient utilement sur ces plates-formes et que seules ces plates-formes, où les moyens les plus naturels de comparaison des pointeurs connexes fonctionneraient également avec des personnes non liées et p> li>
Il existe des plates-formes où la comparaison des pointeurs non liés serait problématique p> li>
ol> Ensuite, il est tout à fait logique pour la norme de considérer les comparaisons de pointeur non liées comme un comportement non défini. Avaient-ils prévu que même des compilateurs pour les plates-formes qui définissent un classement mondial disjoint pour tous les pointeurs pourraient rendre les comparaisons de pointeur non liées nier les lois du temps et de la causalité (par exemple, donnée: p> p1
p1
int needle_in_haystack(char const *hs_base, int hs_size, char *needle)
{
for (int i=0; i<size; i++)
if (hs_base+i == needle) return 1;
return 0;
}
Le Comité n'a pas répondu à cette question spécifique dans sa mission officielle pour la norme, de sorte que toute réponse est spéculative, sauf si possible d'un membre du comité. Néanmoins, la raison officielle des aspects connexes de la spécification considère les architectures segmentées et la destinaçabilité des octets à proximité des représentations d'objets globaux, de sorte que je serais enclin à deviner que @cheersandhth le présente dans cette partie de sa réponse qui fait référence à C.
Il suit, au fait, que, bien que vous peut i> conversation explicitement convertir en
intPTR_T code> et comparer, le résultat ne contient pas nécessairement des informations sur les emplacements relatifs des objets non liés en mémoire. La mettre dans ces termes rend la restriction plus judicieuse pour moi.
Les architectures segmentées font de l'enfer - comme l'ont trouvé sur Intel 80386 et des parents. Il était particulièrement douloureux dans le mauvais vieux temps de 80286, 80186, 8086, 8088. Vous pourriez avoir plusieurs représentations de bits pour la même adresse. Même avec des Pentiums modernes et X86_64s, etc., vous pouvez en théorie avoir des adresses segmentées; Personne n'est assez fou pour les utiliser, cependant. Eh bien, presque personne - je suis sûr qu'il y a des gens qui présentent des logiciels avec des adresses segmentées.
Ce n'est pas une question d'opinion, dans la mesure où je connais tous les comportements non définis dans les normes C et C ++ ont des raisons. Qu'ils soient faciles à discerner de sources publiques, c'est une autre question, mais cela ne leur fait pas de mauvaises questions.
Notez que vous pouvez facilement esquiver ce comportement indéfini en moulant les pointeurs vers des entiers, puis comparez les entiers à la place. 100% de comportement déterministe et bien défini.
@Jonathanleffler Il est toujours assez courant dans les microcontrôleurs, car les anciennes architectures de microcontrôleurs 8/16 bits inventées dans les années 70, 80 et 90 sont toujours utilisées dans la production. Vous aurez une mémoire "bancaire" et toutes sortes de types de pointeur étranges pour y accéder. De nombreux programmeurs intégrés s'accrochent fanatiquement sur cette ancienne merde sans raison sonore.
@LUNDIN: rien dans la norme ne nécessite que les comparaisons de représentations entière donnent les mêmes résultats que les comparaisons des pointeurs, même dans des scénarios où ces derniers sont bien définis. Les programmeurs intégrés doivent souvent être capables de modifier les conceptions existantes. Si un produit a bien vendu pendant dix ans et que les gens continuent à l'acheter, mais une pièce devient indisponible, pouvant utiliser le code existant avec de nouvelles pièces peut être préférable de réécrire tout à partir de zéro. Cela peut être particulièrement vrai pour les produits qui doivent interagir avec d'autres équipements (qui peuvent dépendre de certains ...
... des aspects sans papiers de son comportement, tels qu'un délai entre lorsqu'il voit une certaine entrée et lorsqu'il déclenche une certaine sortie). Être capable d'ingénieur quelque chose avec de nouvelles pièces pouvant servir de remplacement d'une chute pour quelque chose de construction avec des pièces anciennes est très utile dans le monde réel. Je ne suis pas sûr de ce que vous entendez par «pas de raison sonore».
@supercat dans le monde réel 99% de tous les ordinateurs, un pointeur converti en un entier comparera la même chose qu'un pointeur par rapport à un pointeur, car les adresses ne sont que des chiffres dans 99% de tous les ordinateurs. En ce qui concerne s'accrocher à la vieille merde, je faisais plutôt référence à des ingénieurs potentiels qui choisissent un nouveau MCU pour leur nouveau projet et indiquant des choses comme "permettent de prendre la photo parce que c'est le moins cher", puis ils n'ont pas vérifié les prix MCU depuis le milieu 90, encore moins estimé qu'un processeur extrêmement inefficace a besoin d'un éclair beaucoup plus coûteux. Ou "permet de prendre la photo parce que je suis trop paresseux pour apprendre de nouvelles choses".
Les architectures de pic à 8 bits sont très bonnes dans des éléments comme un bit-bit et de nombreux objectifs de systèmes intégrés comportant un accumulateur principal et un grand ensemble de travail accessible en permanence est plus utile que d'avoir un ensemble de 8 ou 16 registres équivalents. Pour certaines sortes de code, le bras peut tourner des cercles autour de la photo, mais pour d'autres types de code, l'inverse est vrai. Sur la photo, la décrémentation d'une variable globale de 8 bits dans la banque commune est une instruction; Sur le bras, c'est 3-4. Sur la photo, définir un bit d'enregistrement d'E / S à l'interruption-Safe Mode est une instruction; sur la plupart des bras ...
... Cela peut être beaucoup plus (nécessitant généralement l'accès d'une séquence d'enregistrement / désactivation / restaurer ou d'utiliser la séquence LDREX / STREX / BNE). D'une perspective architecturale, je ne connais rien de mieux que la photo pour les choses qu'il fait bien, bien que les armes moins chères soient souvent assez bonnes, même à ces fins.