Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Comparaison entre pointeurs

25 réponses
Avatar
Taurre
Bonjour =E0 tous,

En lisant la norme C au sujet du comportement des op=E9rateurs de
comparaisons (<, <=3D, > et =3D>), j'ai vu que dans le cas o=F9 deux
pointeurs r=E9f=E9rencent des objets n'appartenant pas au m=EAme agr=E9gat,=
le
comportement est ind=E9termin=E9 (C11 [n1570] =A7 6.5.8 Relational operator=
s
al 5 pp 95-96).

Comparer l'adresse de deux objets ne faisant pas partie du m=EAme
agr=E9gat ne me para=EEt pas avoir beaucoup de sens, mais j'aurais voulu
savoir pourquoi il s'agit d'un comportement ind=E9termin=E9 ? Je veux
dire, techniquement, les pointeurs ne sont g=E9n=E9ralement rien de plus
que des entiers, aussi, en quoi leur comparaison serait-elle
probl=E9matique hormis les cas cit=E9s par la norme ? Existe-t-il des
architectures recourant =E0 des repr=E9sentations pouvant =EAtre
probl=E9matique en cas de comparaison ? Si oui, auriez-vous des
exemples ?

Merci d'avance pour vos r=E9ponses :)

10 réponses

1 2 3
Avatar
Jean-Marc Bourguet
(Marc Espie) writes:

Il y *a* des archis exotiques. Tous les "undefined behavior" de la norme
en proviennent.



Je ne suis pas sur que ce soit le cas de tous (modifier deux fois un
objet sans point de sequencement entre les modif p.e.), mais une partie.
Et surtout, le plus gros consommateur de ces latitudes, c'est
l'optimiseur. Meme si la raison, c'est une archi exotique, ce qui
risque le plus de poser probleme, c'est l'optimiseur.


Les optimiseurs fonctionnent sur le mode "c'est de l'UB, ca ne peut pas
arriver, j'en deduis tout ce que je peux et je propage l'info le plus
loin possible -- apres et *avant* le moment ou l'UB a lieu -- pour en
profiter". Avec

if (p == NULL) {
// on peut prouver que p n'est pas modifie
}
p->x = 42;

J'ai deja vu une version de gcc virer le if. Qui etait de
l'instrumentation venant d'etre ajoutee pour voir pourquoi le programme
plantait, ce qui etait particulierement perturbant. (Dans ce cas,
l'optimisation a ete viree avant la release de gcc parce que trop
surprenante, mais pas sans debats; gcc continue a faire des choses
analogues pour l'overflow -- au moins il y a -fwrapv pour les supprimer,
mais il n'y a pas de flag, "ne fait que des optimisations raisonnables"
et pour cause, personne n'est d'accord sur la definition d'optimisation
raisonnable).

A+

--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
Antoine Leca
Taurre écrivit :
J'ai reverifie ma norme, la comparaison entre pointeurs non correles est bien
une "undefined behavior".
Il peut donc se passer relativement n'importe quoi dans le cadre du C standard.



C'est en effet ce qui me perturbe. Que la mémoire soit ou non
segmentée, les pointeurs restent des entiers,



... mais il n'est pas garanti par la norme que les entiers (math) en
question soient manipulables en tant qu'entiers C. Exemple le plus
évident : un compilateur C90 pour l'architecture 64 bits de Microsoft:
long est un type 32 bits, et les pointeurs sont sur 64 bits...

Autre exemple : le langage définit le type ptrdiff_t pour traiter les
différence entre pointeurs (sous-entendu « corrélés »). Sur les
architectures mixtes 32/64 (genre x86-64), il est parfaitement légitime
d'utiliser un type sur 32 bits pour ce faire, si le compilateur suppose
par ailleurs que le programme ne va considérer qu'un espace mémoire
limité à 31 ou 32 bits (cas par exemple du modèle "x32") ; et
évidemment, une comparaison entre deux pointeurs « non corrélés » peut
faire exploser les compteurs.

Par ailleurs, l'affirmation « les pointeurs sont des entiers » me gêne
aux entournures. Même si je sais bien que ces temps-ci, «tout le monde»
travaille avec des architectures linéaires. En effet, ce genre
d'affirmation suppose (indument) que les représentations des pointeurs
partagent *toutes* les propriétés des entiers (des ordinateurs,
c'est-à-dire un intervalle en terme mathématique). Et ce n'est en
pratique pas le cas : certaines valeurs ne représentent pas des
pointeurs valables, d'autres valeurs sont magiques, parfois des
différences entre deux valeurs peuvent avoir un sens (comme entre deux
pointeurs vers le même objet), parfois pas (comme par exemple entre deux
déclarations adjacentes de deux pointeurs, qui sont aléatoires, au sens
d'une variable aléatoire), etc.


les comparer ne doit donc pas poser de problème.



Cf. supra pour d'éventuels problèmes.
Par ailleurs, quel est l'intérêt de faire une opération n'ayant pas de
signification ? Juste pour pousser la norme dans ses retranchements ?


Antoine
Avatar
espie
In article <jvomhq$q78$,
Antoine Leca wrote:
Par ailleurs, l'affirmation « les pointeurs sont des entiers » me gêne
aux entournures. Même si je sais bien que ces temps-ci, «tout le monde»
travaille avec des architectures linéaires. En effet, ce genre
d'affirmation suppose (indument) que les représentations des pointeurs
partagent *toutes* les propriétés des entiers (des ordinateurs,
c'est-à-dire un intervalle en terme mathématique). Et ce n'est en
pratique pas le cas : certaines valeurs ne représentent pas des
pointeurs valables, d'autres valeurs sont magiques, parfois des
différences entre deux valeurs peuvent avoir un sens (comme entre deux
pointeurs vers le même objet), parfois pas (comme par exemple entre deux
déclarations adjacentes de deux pointeurs, qui sont aléatoires, au sens
d'une variable aléatoire), etc.



Petite parenthese, j'avais note dans mes commentaires initiaux (qui vont
dans ton sens "en C standard").

Il est *evident* que, dans certains domaines d'application, on fait des
hypotheses supplementaires concernant l'acces a la memoire. Par exemple,
le code noyau d'un Unix-like moderne ecrit en C sur une architecture mainstream
*va* manipuler des pointeurs comme des entiers. Il y a parfois des soucis
concernant le caractere signe ou non de ces pointeurs. Et il y a parfois
quelques soucis concernant certains compilos mainstream qui sont souvent
utilises pour compiler les dits-noyaux (pas tres dur de retrouver des
grosses engueulades entre Linus et l'equipe de dev de gcc), qui mettent
surtout en evidence la necessite pour un compilo *generaliste* d'etre
equipe d'options *permettant de desactiver tout une batterie d'optimisations
user-land* qui vont poser probleme lors de la compilation noyau.

Mais on peut facilement etre d'accord que tout ceci est de l'application
de niche... sauf si on veut bosser sur ce genre de choses, supposer des
choses sur les pointeurs est une connerie.

Suffit d'etre assez vieux pour avoir vu passer quelques generations
d'architecture et voir des hypotheses plus ou moins raisonnables a l'instant
t s'averer completement debiles a l'instant T+1.

Experience perso: le basic amiga, pondu par microsoft, deja mauvais a
l'epoque, qui avait cru intelligent de stocker ses info de gc sur les 8 bits de
poids fort des pointeurs, vu que, sur les premiers amiga, a base de 68000,
le bus d'adresse etait limite a 24 bits...
Avatar
Jean-Marc Bourguet
(Marc Espie) writes:

Experience perso: le basic amiga, pondu par microsoft, deja mauvais a
l'epoque, qui avait cru intelligent de stocker ses info de gc sur les
8 bits de poids fort des pointeurs, vu que, sur les premiers amiga, a
base de 68000, le bus d'adresse etait limite a 24 bits...



Erreur (utiliser les 8 bits de poids forts de pointeur parce que
l'espace memoire est limite a 24 bits) qui a ete faite au moins deux
autres fois. Sur les premier Mac et les IBM 360 (la, c'etait grave au
point que quand ils ont fait l'extension sur 32 bits -- prevue depuis le
debut -- ils n'ont pu utiliser que 31 bits).

L'autre cote de la piece, c'est la reponse "si on n'avait pas fait ca,
on aurait ete moins bon et perdu tant de part de marche qu'on aurait pas
survecu pour en profiter". Difficile pour moi de savoir a quel point
c'est vrai.

Mais c'est fou ce qu'on se traine longtemps les consequences des choix.

A+

--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
espie
In article ,
Jean-Marc Bourguet wrote:
L'autre cote de la piece, c'est la reponse "si on n'avait pas fait ca,
on aurait ete moins bon et perdu tant de part de marche qu'on aurait pas
survecu pour en profiter". Difficile pour moi de savoir a quel point
c'est vrai.



bullshit.
Avatar
Taurre
On 6 août, 00:27, (Marc Espie) écrivit:
Il faut *vraiment* que tu changes de mode de fonctionnement vis-a-vis du
langage, ca t'evitera des problemes.

Les questions du genre "je ne comprend pas, sur toutes les archis que je
connais, ca marche comme ca, comment peut-on faire autrement", c'est la
meilleure facon de chercher les emmerdes.

Il y *a* des archis exotiques. Tous les "undefined behavior" de la norme
en proviennent. Dans certains cas, tu vas avoir du mal a avoir une "preuv e
d'existence", sous forme d'une archi sur laquelle ca chie (deja, tu auras
parfois du mal a trouver des gens qui ont ces archis sous la main ou qui en
ont eu l'experience).

Si tu pars dans l'idee de "oh ben, ca doit etre implemente comme ca, parc e
que je n'arrive pas a imaginer que ca puisse etre autrement", tu auras to t
ou tard des problemes. Plutot tot, en fait, Murphy aidant. Suffit que tu
depende d'un comportement mal defini pour que quelqu'un essaie de faire
tourner ton code sur une archi ou ca chie (ca ne rate presque jamais).

Et meme: c'est un mauvais etat d'esprit pour faire du code robuste, donc
de qualite, et encore plus si tu veux faire de la securite informatique.

Il faut beaucoup, beaucoup d'imagination pour trouver toutes les facons d ont
un code peut merder. Mais en fait, ca n'est pas important, parce qu'il y a
une seule facon dont ce code peut marcher... c'est beaucoup plus simple,
et infiniment moins generateur d'emmerdes, de decider qu'on va se placer
dans LE cas ou les choses marchent, LE cas du comportement defini.

A force de vouloir avoir des contre-exemples... on en oublierait presque
qu'au final, le but, c'est de faire des choses qui fonctionnent.



En fait, ma question tient purement de la curiosité (peut-être
malsaine, j'avoue). Lorsque je programme, j'essaye de me tenir à la
norme afin de maximiser la portabilité de mon code. Cependant, j'aime
toujours de savoir d'où provient telle ou telle restriction et
d'apprendre comment certaines architectures implémentent les concepts
du C. C'est entre autre pour cela que j'aime poser mes questions au
sujet de la norme ici, car je sais qu'il y a des gens d'expérience qui
pourront le plus souvent m'éclairer avec du concret.

Sinon, merci à tous pour vos réponses, je pense désormais mieux voir
dans quels cas de tels comparaisons pourraient être problématique.
Avatar
Tonton Th
On 08/06/2012 09:46 AM, Jean-Marc Bourguet a dit:

surprenante, mais pas sans debats; gcc continue a faire des choses
analogues pour l'overflow -- au moins il y a -fwrapv pour les supprimer,
mais il n'y a pas de flag, "ne fait que des optimisations raisonnables"



Même -O0 ?


--

Nous vivons dans un monde étrange/
http://foo.bar.quux.over-blog.com/
Avatar
Jean-Marc Bourguet
Tonton Th writes:

On 08/06/2012 09:46 AM, Jean-Marc Bourguet a dit:

surprenante, mais pas sans debats; gcc continue a faire des choses
analogues pour l'overflow -- au moins il y a -fwrapv pour les supprimer,
mais il n'y a pas de flag, "ne fait que des optimisations raisonnables"



Même -O0 ?



Ça c'est "ne faut aucune optimisation, même pas les raisonnables et
tellement évidente que les autres compilateurs ne permettent pas de les
supprimer."

A+

--
Jean-Marc
FAQ de fclc: http://www.levenez.com/lang/c/faq
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
Tonton Th
On 08/06/2012 06:05 PM, Jean-Marc Bourguet a dit:

Erreur (utiliser les 8 bits de poids forts de pointeur parce que
l'espace memoire est limite a 24 bits) qui a ete faite au moins deux
autres fois. Sur les premier Mac et les IBM 360 (la, c'etait grave au
point que quand ils ont fait l'extension sur 32 bits -- prevue depuis le
debut -- ils n'ont pu utiliser que 31 bits).



Tu as oublié les premières série des Atari ST (ceux à 68000) où
les accès aux périphériques (68901 et ay3-8910) pouvaient se faire
bien plus rapidement en négligeant les 8 bits de poids fort du
bus d'adresse. Bien pratique en asm/superviser, mais diabolique
à gérer en C ;)

--

Nous vivons dans un monde étrange/
http://foo.bar.quux.over-blog.com/
Avatar
espie
In article <50bb907e$0$1952$,
Tonton Th wrote:
On 08/06/2012 09:46 AM, Jean-Marc Bourguet a dit:

surprenante, mais pas sans debats; gcc continue a faire des choses
analogues pour l'overflow -- au moins il y a -fwrapv pour les supprimer,
mais il n'y a pas de flag, "ne fait que des optimisations raisonnables"



Même -O0 ?



-O0 fait parfois des non-optimisations pas raisonnables du tout, comme
de deposer des zeros dans les variables non initialisees.

(je crois que ca a finalement ete corrige en 4.x)
1 2 3