7
votes

Testez les pointeurs en utilisant un opérateur relationnel pour la boucle

Supposons que j'ai la boucle pour la boucle qui stocke les zéros dans un tableau à l'aide de pointeurs comme celui-ci:

int *vp, values[5];

for(vp = &values[5-1]; vp >= &values[0]; vp--)
   *vp = 0;


7 commentaires

Il est «indéfini», mais sur 95% des systèmes, tout ira bien. Le scénario seul où la comparaison échouera sera si et valeurs [0] == 0x0.


Probablement plus de 95%. =)


Je parierai qu'il ne fonctionnerait pas sur la mise en œuvre de C sur des machines Symbolics Lisp. Je n'ai aucune idée de savoir s'il y a toujours une utilisation, cependant; La société a été étrangère il y a presque 20 ans.


Je le reprends, cela aurait pu travailler. Symbolique C vérifie les limites effectuées, mais je ne pense que lorsque des pointeurs de déséroférance. Comme cela ne contient pas de la déréférence, il a probablement fonctionné car vp commence à pointer sur le même objet de tableau. Ses pointeurs ont été mis en œuvre comme une paire de tableau , index , et je ne pense pas qu'il y avait un problème avec index décrémentation ci-dessous 0.


Y a-t-il une raison spécifique que vous n'utilisez pas d'inégalité directe avec un post-décrément. Quelque chose comme pour (vp = valse + n; vp--! = Valeurs;) n est la magnitude de votre tableau?


@Whozcraig c'est une question de style


@ Richardj.rossiii Je demandais spécifiquement de répondre à l'observation de l'OP du texte mentionné sur l'évaluation d'un pointeur basé sur une matrice avant le premier élément, qui est en fait non défini, plutôt que sur un dernier élément, que est défini par la norme. Je n'ai pas voulu que ce soit un commentaire "C'est un autre moyen" et s'excuse s'il a été pris en tant que tel.


3 Réponses :


2
votes

En supposant qu'un pointeur équivaut à un entier non signé, nous pouvons voir que le problème n'existerait que si valeurs a commencé à l'adresse 0, auquel cas le pointeur envelopperait après avoir été décrémenté et devenir uint_max .

Pour visualiser le problème, passons à travers ce qui se passe, en supposant que valeurs commence à l'adresse 0x0: xxx < P> Ainsi, vp ne serait jamais inférieur à la valeur minimale d'un pointeur (qui correspond à une boucle infinie (en supposant que toute la mémoire est écritable) ou une défaillance de la segmentation.

Il s'agit également de comportement non défini en fonction de la norme (comme vous pouvez aborder un élément après un tableau, mais pas avant de cela), mais en réalité, cela ne devrait jamais échouer sur un système réaliste.


4 commentaires

Donc, il est prudent d'utiliser ceci ou je peux vérifier plus que possible.


@ ashish2expert oui, c'est mon évaluation qu'il est sûr, à moins que vous traitiez avec un système très étrange (que vous n'êtes probablement pas ici).


Ce code peut échouer sur les implémentations avec des pointeurs de segment et décalage, mais cela peut également échouer car l'optimiseur est autorisé à supposer que vp> = & valeurs [0] n'est jamais exécuté avec vp < / code> ne pointant pas sur un élément du tableau ou un au-delà (parce que cela serait un comportement indéfini). Par conséquent, l'optimiseur peut se comporter comme si cette expression est toujours vraie et peut l'éliminer, entraînant une boucle infinie.


@ERICPOSTPISCHIL Dans ce cas, je pense que votre optimiseur doit être moins optimisante.



4
votes

Ce code n'est pas en sécurité, même si des architectures anciennes ou exotiques du processeur sont exclues.

L'optimiseur d'un compilateur intègre de nombreuses règles sur la langue. Quand il voit vp> = et valeurs [0] , où valeurs est une matrice, l'optimiseur est autorisé à supposer que vp pointe sur un tableau élément ou un au-delà de la matrice, car sinon l'expression n'est pas définie par le langage C.

Les règles et mécanismes intégrés dans l'optimiseur peuvent donc décider que vp> = & valeurs [0] est toujours vrai, il peut donc produire du code comme si pour (vp = & valeurs [5 -1];; VP -) avait été écrit. Il en résulte une boucle sans condition de résiliation et un comportement supplémentaire non défini lorsque * vp = 0 est évalué avec vp pointant en dehors du tableau.


2 commentaires

Oui, c'est possible, mais c'est probablement un peu improbable, à moins que vous n'ayez certains drapeaux d'optimisation définis. Si je me souviens bien, GCC a une option qui brise des boucles comme ça, mais elle est désactivée par défaut, et Clangs Optimizer ne touchera même pas de choses comme ça.


@ RICHARDJ.ROSSIII: Conservez-vous que ce code est en sécurité selon la norme C, ou simplement en sécurité si vous avez des connaissances spécifiques sur certains compilateurs? S'il vous plaît citer la documentation en supportant cela.



0
votes
int *vp, values[5];

for(vp = &values[5-1]; vp ; vp = (vp > &values[0]) ? vp-1 : NULL; ) {
   *vp = 0;
   } 

0 commentaires