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

ordre d'évaluation des booléens

19 réponses
Avatar
Miguel
Bonsoir
Voilà, j'ai une petite question pas trop méchante, mais qui a éveillé ma
curiosité.
Pour faire simple, je commence par ma fonction:

int left(int x, int y)
{
while(laby[x-1][y] == '.' && x-1 >= 0 ) x--;
return x;
}

qui est censé me donner l'abscisse du point le plus à gauche sur cette ligne
(en s'arrêtant aux "obstables" != '.').

Supposons qu'on arrive à la colonne 0, on a l'évaluation suivante:
(laby[-1][y] == '.' && -1 >=0) qui est fausse, bien sûr.
que va me donner le prog à l'exécution de la fonction dans ce cas?
Y a-t-il un moyen de faire évaluer le x >= 0 en premier pour éventuellement
éviter le laby[x][y]?

J'imagine que quoo qu'il en soit les 2 booléennes sont évaluées, mais ce
n'est que conjecture.
Merci
Miguel

10 réponses

1 2
Avatar
Stephane Zuckerman
Bonsoir,

int left(int x, int y)
{
while(laby[x-1][y] == '.' && x-1 >= 0 ) x--;
return x;
}

[...]


J'imagine que quoo qu'il en soit les 2 booléennes sont évaluées, mais ce
n'est que conjecture.


A ma connaissance en C, l'évaluation (faite de gauche à droite) s'arrête
immédiatement lorsqu'une condition booléenne est fausse (les && et || sont
même qualifiés de « courts-circuit »). Maintenant, peut-être me trompé-je
;-)

Stéphane.

--
"Je deteste les ordinateurs : ils font toujours ce que je dis, jamais ce
que je veux !"
"The obvious mathematical breakthrough would be development of an easy
way to factor large prime numbers." (Bill Gates, The Road Ahead)

Avatar
zwim
Le Wed, 28 Apr 2004 22:05:36 +0200, Miguel à écrit
Bonsoir
Voilà, j'ai une petite question pas trop méchante, mais qui a éveillé ma
curiosité.
Pour faire simple, je commence par ma fonction:

int left(int x, int y)
{
while(laby[x-1][y] == '.' && x-1 >= 0 ) x--;
return x;
}

qui est censé me donner l'abscisse du point le plus à gauche sur cette ligne
(en s'arrêtant aux "obstables" != '.').

Supposons qu'on arrive à la colonne 0, on a l'évaluation suivante:
(laby[-1][y] == '.' && -1 >=0) qui est fausse, bien sûr.
que va me donner le prog à l'exécution de la fonction dans ce cas?
Y a-t-il un moyen de faire évaluer le x >= 0 en premier pour éventuellement
éviter le laby[x][y]?

J'imagine que quoo qu'il en soit les 2 booléennes sont évaluées, mais ce
n'est que conjecture.
Merci
Miguel



C'est évalué de gauche à droite, justement pour éviter de scinder sur
plusieurs instructions de test. Dès que le test peut-être décidé,
l'évaluation s'arrête.

Donc a && b, n'évalue que a si a est faux
Donc a || b, n'évalue que a si a est vrai

if(a && b)
{
instructions;
}

est strictement équivalent à

if(a)
{
if(b)
{
instructions;
}
}

****************

if(a || b)
{
instructions;
}

est strictement équivalent à

if(a)
{
instructions;
}
else if(b)
{
instructions;
}




--
zwim.
Rien n'est impossible que la mesure de la volonté humaine...

Avatar
Miguel
Merci à vous 2, j'ai eu la réponse à ma question existentielle de jour.
Avatar
Alexandre BACQUART
Miguel wrote:
int left(int x, int y)
{
while(laby[x-1][y] == '.' && x-1 >= 0 ) x--;
return x;
}


Avant toute chose, je te suggère plutôt de placer les colonnes (x) en
2ème dimension (laby[y][x]) pour alléger l'arithmétique des pointeurs
sur ce genre d'algo (même si tu ne l'utilises pas directement avec *).
En gros, toujours essayer de mettre en dernière dimension celle qui sera
le plus souvent modifiée.

qui est censé me donner l'abscisse du point le plus à gauche sur cette ligne
(en s'arrêtant aux "obstables" != '.').


A lire ton code, ca va plutôt donner le premier caractère différent de
'.' le plus à droite, ce qui n'a rien à voir. L'exposé est un peu
confus, mais je pense que pour obtenir ce que tu cherches :

int left(int x, int y)
{
do { x--; } while(x>=0 && laby[x][y]=='.');
return x; /* -1 si pas trouvé */
}

Tu peux remettre a ta sauce si tu n'aimes pas les do-while (n'oublie
pas le x--; d'amorçage), mais le principe est le même.

Supposons qu'on arrive à la colonne 0, on a l'évaluation suivante:
(laby[-1][y] == '.' && -1 >=0) qui est fausse, bien sûr.


Elle a surtout un comportement indéfini. L'expression laby[-1][y] est
évalué avant -1 >= 0. Autrement dit, avant même que tu testes si tu
débordes, tu fais un accès read en dehors du tableau (y octets avant
le début pour être précis). Il peut y avoir n'importe quoi à cet endroit.

que va me donner le prog à l'exécution de la fonction dans ce cas?


Indéfini, mais dans la plupart des cas, ton left() retourne 0 je pense.

Y a-t-il un moyen de faire évaluer le x >= 0 en premier pour éventuellement
éviter le laby[x][y]?


Je te l'ai écris en haut.

J'imagine que quoo qu'il en soit les 2 booléennes sont évaluées, mais ce
n'est que conjecture.


Non ! c'est important ! il ne faut pas négliger ça :

------------------------------
(E1) && (E2)
E1 toujours evalué en premier. E2 évalué SEULEMENT si E1 est vrai.
------------------------------
(E1) || (E2)
E1 toujours evalué en premier. E2 évalué SEULEMENT si E1 est faux.
------------------------------



--
Tek
int main(void) {printf("Free The World !");} /* copyleft */

Avatar
Vincent Lefevre
Dans l'article <40902962$0$22864$,
Miguel écrit:

Merci à vous 2, j'ai eu la réponse à ma question existentielle de jour.


La réponse devait sûrement être dans la FAQ. Si tu ne l'as jamais lue,
je te conseille d'aller la voir (et si tu ne sais pas où la trouver,
Google fait certainement l'affaire, comme d'habitude)...

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% validated (X)HTML - Acorn / RISC OS / ARM, free software, YP17,
Championnat International des Jeux Mathématiques et Logiques, etc.
Work: CR INRIA - computer arithmetic / SPACES project at LORIA

Avatar
Bertrand Mollinier Toublet
Alexandre BACQUART a signe':
int main(void) {printf("Free The World !");} /* copyleft */


Outre le fait que ta signature invoque un comportement indefini (printf,
une fonction variadique, est appelee sans prototype en vue), j'ai pas
bien suivi les implications et sens cache. Tu veux developper, s'il te
plait ?

Je note au passage que ma signature (quote choisi au hasard) s'accorde
tres bien avec le sujet du post :-D

--
Bertrand Mollinier Toublet
"The open-source movement is a communist affront to capitalism and
should not be allowed to interfere in the profitable business of
proprietary software" -- SCO on the Linux community.

Avatar
Pierre Maurette
zwim typa:
[...]
****************

if(a || b)
{
instructions;
}

est strictement équivalent à

if(a)
{
instructions;
}
else if(b)
{
instructions;
}
On pourrait l'écrire :


if(a) goto positif;
else if(b)
positif:
{
/* instructions */
}

Ainsi, pas de duplication de instructions.



Plus sérieusement, et pour compléter:

C99 6.5.13.4:
"Unlike the bitwise binary & operator, the && operator guarantees
left-to-right evaluation; there is a sequence point after the
evaluation of the first operand. If the first operand compares equal
to 0, the second operand is not evaluated."

C99 6.5.14.4:
"Unlike the bitwise | operator, the || operator guarantees
left-to-right evaluation; there is a sequence point after the
evaluation of the first operand. If the first operand compares unequal
to 0, the second operand is not evaluated."

Ce qui veut dire qu'AMHA, un compilateur C ne devrait pas pouvoir
proposer d'option "Evaluation booléenne complète". Faut le faire à la
main. En se méfiant des optimisations.

Pierre

Avatar
Marc Boyer
Pierre Maurette wrote:
Ce qui veut dire qu'AMHA, un compilateur C ne devrait pas pouvoir
proposer d'option "Evaluation booléenne complète". Faut le faire à la
main. En se méfiant des optimisations.


Ou alors, on joue avec & et | et des == 1

Eval complète de
a && b
se fait avec
a == 1 & b == 1

Marc Boyer
--
La contractualisation de la recherche, c'est me donner de l'argent pour
faire ce que je ne sais pas faire, que je fais donc mal, pendant que ce
que je sais faire, je le fais sans moyens...

Avatar
Pierre Maurette
Marc Boyer typa:

Pierre Maurette wrote:
Ce qui veut dire qu'AMHA, un compilateur C ne devrait pas pouvoir
proposer d'option "Evaluation booléenne complète". Faut le faire à la
main. En se méfiant des optimisations.


Ou alors, on joue avec & et | et des == 1

Eval complète de
a && b
se fait avec
a == 1 & b == 1


Si a et b sont des expressions composées, il est peut-être plus sûr de
faire :
a != 0 & b != 0

J'aurais encore des craintes par rapport à une optimisation. Le
compilateur sait que les comparaisons ne peuvent renvoyer que 0 ou 1,
et en tirer des conclusions. Ceci dit, si j'ai une raison valable de
souhaiter une évaluation complète, il ne devrait pas y avoir de
problème. Il y a dans a et/ou b soit des appels de fonctions, soit des
données que j'aurais déclaré volatiles.

Au pire :

volatile int tempo;
...
tempo = (a != 0);
tempo &= (b != 0);

--
Pierre


Avatar
Alexandre BACQUART
Bertrand Mollinier Toublet wrote:
Alexandre BACQUART a signe':
int main(void) {printf("Free The World !");} /* copyleft */


Outre le fait que ta signature invoque un comportement indefini (printf,
une fonction variadique, est appelee sans prototype en vue), j'ai pas
bien suivi les implications et sens cache. Tu veux developper, s'il te
plait ?


J'utilise cette signature depuis des années, surtout par mail, j'avoue
ne plus y faire très attention (mise à part les dernières corrections
pour satisfaire les tatillons). A la base, c'est plus un délire qu'autre
chose, ce n'est PAS le corps du message, comme semble d'ailleurs
l'indiquer le "--" séparateur classique des NG, ce n'est pas non plus un
cours pour savoir comment faire du "Hello World" X-plateformes ce dont
tout programmeur C est censé savoir, c'est une signature, juste un clin
d'oeil, histoire d'informer le lecteur (pas forcément ce NG au passage)
que je pratique la programmation en C et que j'affectionne
particulièrement le concept de copyleft. C'est tout. Et surtout, ne pas
essayer d'y voir de sens caché, il n'y en a tout simplement pas. Cette
signature ne traduit aujourd'hui que mon incapacité à trouver
quelque-chose d'original dans ce domaine, l'utilisant depuis si longtemps.

Bref, je ne cherche à interpeller personne en particulier, si c'est ça
que tu veux savoir, car je pensais que l'interprétation de cette
signature n'était pas de nature à intéresser qui que ce soit. Ce n'est
qu'une signature. Je me suis trompé. J'avoue être amusé de constater
qu'ici elle semble plus attirer l'oeil averti que le véritable sujet du
message auquel je répond.

Je crois avoir assez développé là-dessus :)

Je note au passage que ma signature (quote choisi au hasard) s'accorde
tres bien avec le sujet du post :-D


Ce qui n'est pas une nécessité. Et malgré son interprétation bien plus
intéressante que la mienne, elle ne s'accorde qu'au sujet d'un post sur
l'open-source (encore que copyleft, ce n'est pas pareil mais bon) qui
est lui même HS, ne l'oublie pas :) Alors que la mienne, certes pas
portable (voire même pas compilable du tout dans l'absolu, je tiens à
préciser pour ma gouverne que j'en ai toujours été tout à fait
conscient) aura eu le mérite, après toutes ces années, de lancer un
débat sur cette grande question : comment faire un "Hello World !"
portable ?

Enfin comme je ne voudrais donner de mauvaises habitudes à personne
(comme oublier d'inclure le sacro-saint "stdio.h" lorsqu'on utilise ses
prototypes, problème très courant en effet et source de bien des ennuis
insurmontables), et pour éviter de donner des boutons aux sensibles,
j'ai pensé à :

--
Tek
"'Free software' is a matter of liberty, not price.", Richard STALLMAN.

Ce n'est pas un programme, mais c'est un bon début et le message a de
plus le mérite d'être relativement neutre. Et puis tout bien réfléchi non :

--
Tek

qui n'est pas copyleft, encore moins C89 ou que sais-je encore, et
surtout complètement vide de sens, mais qui à ce titre aura au moins le
mérite de ne lancer aucun débat métaphysique HS. J'irai même jusqu'à
dire qu'elle tape le poing sur la table en remettant en question la
véritable identité d'une signature (par pseudonyme j'entends).


Content ? :)


--
Tek


1 2