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

Affectation et opérateurs logiques

26 réponses
Avatar
Romuald
Bonjour,

L'autre jour j'ai pu =E9crire, en pensant que c'=E9tait tout =E0 fait l=E9g=
al,
quelque chose comme :

v =3D a + (p !=3D NULL) ? 0 : 1;

J'ai =E9t=E9 surpris de voir que le r=E9sultat n'=E9tait pas celui que
j'attendais. Je me suis mis =E0 chercher (dans la norme C99) o=F9 =E9tait l=
e
comportement ind=E9fini l=E0-dedans et je pense l'avoir trouv=E9 :

A propos de l'affectation : "The side effect of updating the stored
value of the left operand shall
occur between the previous and the next sequence point." et "If an
attempt is made to modify
the result of an assignment operator or to access it after the next
sequence point, the
behavior is undefined."
Sachant que, =E0 propos de l'op=E9rateur ternaire : "The first operand is
evaluated; there is a sequence point after its evaluation.".

Apr=E8s l'=E9valuation de "p !=3D NULL" l'affectation n'est pas termin=E9e =
et
pourtant c'est l=E0 le "sequence point" suivant, d'o=F9 le comportement
ind=E9fini.

Je pense que j'ai bon ?

Vu comment les op=E9rateurs de comparaison && et || fonctionnent =E7a
voudrait dire qu'on ne peux pas affecter =E0 une variable le r=E9sultat de
ces op=E9rateurs ? Tout porte =E0 le croire mais j'ai du mal =E0 comprendre
pourquoi le langage l'interdirait* ?

Merci d'avance !

* Ok, c'est juste "comportement ind=E9fini", c'est pas "interdit", mais
on se comprend !

6 réponses

1 2 3
Avatar
Antoine Leca
Vincent Lefevre écrivit :
Vincent Lefevre writes:
Mais ça ne parle pas des cas les plus tordus, comme: a[a[i]] = 0;
dans le cas où a[i] == i.





La norme dit (6.5#2): "Between the previous and next sequence point
an object shall have its stored value modified at most once by the
evaluation of an expression. Furthermore, the prior value shall be
read only to determine the value to be stored."

Considérons l'objet a[i] et supposons a[i] == i. La valeur stockée
va être modifiée. Donc la lecture de a[i] ne doit servir qu'à
déterminer la valeur à être stockée (pas à autre chose, cf le
"only"). Mais dans le code ci-dessus, la lecture de a[i] sert
à tout autre chose: à déterminer l'adresse de l'objet.



La torsion ici est celle que ne permet pas le texte de la norme (tant
C90 que C99), qui n'est pas suffisamment souple pour pouvoir prendre en
compte ton expression, comme tu l'expliques. Le comportement du code est
donc officiellement indéfini, autrement dit une telle expression ne doit
pas être utilisée dans du code destiné à être portable ;
pourtant on sent intuitivement que « cela devrait passer ».

Il s'agit donc d'un cas où la norme précise une limite en-deçà de ce
qu'elle pourrait permettre (du point de vue des programmeurs), au profit
en l'occurrence des analyseurs syntaxiques (d'habitude, c'est au profit
des optimisations potentielles du code produit ;-))
En gros, il s'agit [s'agissait] de ne pas rendre l'opération STORE
impliquée par l'opérateur = comme étant spéciale au niveau de l'ordre
des opérations à l'intérieur d'une séquence.


Pour faire encore plus compliqué, la décision a été prise au niveau du
comité de modifier la norme à ce niveau. C'est ainsi que pour la
prochaine révision, il est spécifié que « l'effet de modifier la valeur
stockée est subséquent au calcul de la valeurs des deux opérandes gauche
et droite, » [N1539 6.5.16p3] ce qui rend légitime l'expression en
question (ou rendra illégitime les analyseurs syntaxiques,
algorithmiques ou humains, qui ronchonnent sur une telle expression).


Maintenant, au niveau où se place la FAQ, entrer dans de tels détails
sur les évolutions de la norme serait franchement déplacé (ÀMHA).
D'ailleurs, il apparaît que les questions portant sur des formulations «
tordues » ne sont formulées que par des analystes du langage (csc),
tandis que les programmeurs ne s'intéressent généralement qu'à des
expressions plus simples comme a[i++]=, qui sont abordées par la FAQ.


Antoine
Avatar
espie
In article <20110210021413$,
Vincent Lefevre wrote:
Dans l'article ,
Jean-Marc Bourguet écrit:

Vincent Lefevre writes:



> Mais ça ne parle pas des cas les plus tordus, comme: a[a[i]] = 0;
> dans le cas où a[i] == i.



Je ne vois pas de probleme ici. (On ne se sert pas de ce qui est modifie
pour autre chose que la determination de ce qui est modifie ou de sa
nouvelle valeur, ce qui me semble-t'il est autorise).



La norme dit (6.5#2): "Between the previous and next sequence point
an object shall have its stored value modified at most once by the
evaluation of an expression. Furthermore, the prior value shall be
read only to determine the value to be stored."

Considérons l'objet a[i] et supposons a[i] == i. La valeur stockée
va être modifiée. Donc la lecture de a[i] ne doit servir qu'à
déterminer la valeur à être stockée (pas à autre chose, cf le
"only"). Mais dans le code ci-dessus, la lecture de a[i] sert
à tout autre chose: à déterminer l'adresse de l'objet.



C'est pas pour dire, mais la, c'est du vice.

Norme ou pas norme, il ne me viendrait JAMAIS a l'idee de laisser du code
aussi tordu en l'etat. Il est clair qu'il va tot ou tard y avoir un souci,
et c'est pas le pouieme de performance que tu peux gagner en ecrivant des
horreurs pareilles qui justifie le temps passe a debugguer le compilo/le
code/la norme pour en tirer quelque chose de sense...
Avatar
Jean-Marc Bourguet
Antoine Leca writes:

Jean-Marc Bourguet écrivit :
Il y a eu une serie de tentative de clarifications. La derniere en date
(et la seule qui a passe le stade de papier preparatoire) est celle du
C++ qui abandonne totalement la notion de point de sequencement en la
replacement par un ordre partiel sur les operations



As-tu une référence pour le papier en question ?
Histoire de m'éviter de devoir ingérer la totalité de C++0 x ;-)



Cherche dans les documents ecrits par Boehm (et suis un peu les
co-auteurs de ceux-ci, en particulier celui dont le nom m'echappe pour
le moment, qui est aussi dans le comite C).

Ma comprehension est qu'elle devrait etre reprise dans la prochaine norm e C.



Pour le moment, le document de travail (qui en est à l'étape de projet
publié, CD, autrement dit le cadre est supposé fixé) a gar dé la notion
de points de succession mais a ajouté une notion explicite d'ordre
(partiel) des opérations élémentaires et jalons que sont l es points de
succession. C'est intéressant mais je trouve que cela devient
franchement plus technique que cela ne l'était ; cela étant, je ne
connais pas grand chose aux analyseurs syntaxiques algorithmiques,
j'espère qu'ils peuvent faire grand profit de la nouvelle rédac tion.



Ils vont pas nous faire une crise de NIH et se decider pour description
differente sensee etre equivalente j'espere? De ce que j'avais suivi du
cote C++, il y avait eu un effort pour etre utilisable en C avec un
minimum de changements.

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
Jean-Marc Bourguet
Antoine Leca writes:

Jean-Marc Bourguet écrivit :
Cherche dans les documents ecrits par Boehm (et suis un peu les
co-auteurs de ceux-ci, en particulier celui dont le nom m'echappe pour
le moment, qui est aussi dans le comite C).



P.J. Plaugher ? Lawrence Crowl ? Clark Nelson ?



Je pensais au deuxieme mais le troisieme me dit qqch. J'ai pas remarque
P.J. dans les discussions sur ce sujet.

Ils vont pas nous faire une crise de NIH et se decider pour description
differente sensee etre equivalente j'espere? De ce que j'avais suivi du
cote C++, il y avait eu un effort pour etre utilisable en C avec un
minimum de changements.



Mmmm... c'est bien ce que je suis en train d'essayer de comprendre !



Bon, des choses en plus a mettre dans ma pile. Elle s'ecroule...

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
Vincent Lefevre
Dans l'article <ij0ehd$h71$,
Antoine Leca écrit:

Maintenant, au niveau où se place la FAQ, entrer dans de tels détails
sur les évolutions de la norme serait franchement déplacé (ÀMHA).
D'ailleurs, il apparaît que les questions portant sur des formulations «
tordues » ne sont formulées que par des analystes du langage (csc),
tandis que les programmeurs ne s'intéressent généralement qu'à des
expressions plus simples comme a[i++]=, qui sont abordées par la FAQ.



Ceci dit, je me demande si un optimiseur pourrait involontairement
casser une expression du style "a[a[i]] = 0;" quand a[i] == i (dans
l'hypothèse où le programmeur ignorerait ce qu'implique la norme à
ce propos). En effet, d'après la norme, cette expression ne peut pas
modifier la valeur de a[i] (que l'on ait a[i] == i ou non, le premier
cas étant en fait un UB), et plus généralement, dans "a[E] = 0;", la
valeur de E ne peut pas être modifiée. Si l'optimiseur est capable de
prendre en compte cette information (par une bête reconnaissance de
sous-expressions communes), et si a[i] est utilisé en lecture dans
le code qui suit, alors le code généré risque de reprendre la valeur
précédente de a[i] (e.g. qui se trouve dans un registre) au lieu de
sa nouvelle valeur (par lecture mémoire).

--
Vincent Lefèvre - Web: <http://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / Arénaire project (LIP, ENS-Lyon)
Avatar
Vincent Lefevre
Dans l'article <20110210151540$,
Vincent Lefevre écrit:

Ceci dit, je me demande si un optimiseur pourrait involontairement
casser une expression du style "a[a[i]] = 0;" quand a[i] == i (dans
l'hypothèse où le programmeur ignorerait ce qu'implique la norme à
ce propos). En effet, d'après la norme, cette expression ne peut pas
modifier la valeur de a[i] (que l'on ait a[i] == i ou non, le premier
cas étant en fait un UB), et plus généralement, dans "a[E] = 0;", la
valeur de E ne peut pas être modifiée. Si l'optimiseur est capable de
prendre en compte cette information (par une bête reconnaissance de
sous-expressions communes), et si a[i] est utilisé en lecture dans
le code qui suit, alors le code généré risque de reprendre la valeur
précédente de a[i] (e.g. qui se trouve dans un registre) au lieu de
sa nouvelle valeur (par lecture mémoire).



Pour donner un exemple, un compilateur pourrait traduire la fonction
suivante:

int test (int *a, int i)
{
a[a[i]] = 0;
return a[i];
}

comme si le programmeur avait écrit:

int test (int *a, int i)
{
int j = a[i];
a[j] = 0;
return j;
}

(car cela peut donner du code plus rapide).

Mais si le programmeur appelle la fonction dans le cas où a[i] = i
et s'attend à obtenir 0, il aura une mauvaise surprise...

--
Vincent Lefèvre - Web: <http://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / Arénaire project (LIP, ENS-Lyon)
1 2 3