1

Une fois j'avais cru lire, ici ou ailleurs, que dans le cas d'un test du type
if(f() || g())
l'ordre d'exécution des fonctions f et g n'était pas garanti, ou un truc du genre, ça vous dit quelque chose ?

Edit: si un modérateur passe, il serait gentil d'enlever le premier accent dans "éxécution" dans le titre tongue
avatar
Combien de tas de bois une marmotte pourrait couper si une marmotte pouvait couper du bois ?

2

3

|| étant un opérateur "paresseux", je dirais que f est exécutée, et que g n'est exécutée que si c'est nécessaire (si f a renvoyé un résultat faux, donc)
l'ordre d'exécution serait donc garanti : toujours f avant g

non ?
avatar
Tutorial C (TI-89/92+/v200) - Articles Développement Web (PHP, Javascript, ...)
« What is the sound of Perl? Is it not the sound of a wall that people have stopped banging their heads against? » - Larry Wall

4

&& et || sont des sequence points, donc c'est un des rares cas où l'ordre d'exécution est garanti. (Ceci est valable pour le C et le C++, je ne connais pas ce genre de détails pour le C#.)
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

5

tous> je suis rassuré j'ai dû rêver alors grin
avatar
Combien de tas de bois une marmotte pourrait couper si une marmotte pouvait couper du bois ?

6

Si mes souvenirs sont bons, f est bien garanti être appelé avant g. Même que la norme garantit que g ne sera pas appelé si f retourne vraie.

7

Par contre, ce n'est pas le cas dans tous les langages.

De manière générale, c'est le cas dans les langages dérivés/inspirés du C (C, C++, PHP, Perl, JavaScript, ... avec la particularité que Perl et JS ne renvoient pas un booléen, mais la valeur de l'opérande)
Mais ce n'est pas le cas en (notamment) Visual Basic (en VB .NET, ils ont d'ailleurs rajouté OrElse et AndAlso pour ça ^^ )ok
avatar
Tutorial C (TI-89/92+/v200) - Articles Développement Web (PHP, Javascript, ...)
« What is the sound of Perl? Is it not the sound of a wall that people have stopped banging their heads against? » - Larry Wall

8

Au passage, il me semble que java garantit que toutes les expressions sont évaluées de gauche à droite.

donc, apparemment, || est évalué de gauche à droite, mais pour |, ça dépend, c'est ça?

9

Effectivement, | n'est pas un sequence point, donc aucun ordre d'évaluation n'est garanti.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

10

En JAVA tout n'est pas évalué de gauche a droite, ca dépend des opérateurs mais le sens est en effet garanti par les specs.
Les affectation notamment fonctionnent de droite à gauche ce qui fait que l'on peut faire le classique x=y=z=10;
avatar

11

Ah oui c'était peut-être pour le | oui.

Et dans le cas de
f(g(), h())l'ordre d'exécution de g et h est indéterminé non ?
avatar
Combien de tas de bois une marmotte pourrait couper si une marmotte pouvait couper du bois ?

12

Indéderminé par les standards du C, oui.
Après tu peux te renseigner sur ton compilateur qui le spécifie peut-être dans ca doc, mais il faudra te souvenir que ce n'est valable pour tous
avatar

13

Et même pour une compilo donné, ça peut changer suivant l'optimisation...

Sinon il suffit de lire la gramaire du C pour voir l'ordre de précédence des opérateurs...
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

14

ça dépend carrément de l'optimisation de l'expression en cours, puisque le but est d'économiser les registres.
Seul java garantit un ordre d'évaluation.

15

Uther (./10) :
En JAVA tout n'est pas évalué de gauche a droite, ca dépend des opérateurs mais le sens est en effet garanti par les specs.
Les affectation notamment fonctionnent de droite à gauche ce qui fait que l'on peut faire le classique x=y=z=10;

Euh non là pas du tout, tu confonds associativité et ordre d'évaluation : l'associativité, c'est ce qui fait que x-y-z est compris comme (x-y)-z et pas x-(y-z) ; alors que l'ordre d'évaluation, c'est ce qui fait que x+(x++) équivaut à 2*(x++) et pas à 2*(x++)+1 (en Java en tout cas, en C c'est du code invalide)

Cela dit c'est vrai que l'ordre d'évaluation est bien défini en Java, mais ça ne dépend pas de l'opérateur et c'est toujours de gauche à droite : http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#4779

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

16

squalyl (./14) :
ça dépend carrément de l'optimisation de l'expression en cours, puisque le but est d'économiser les registres.
Seul java garantit un ordre d'évaluation.

En effet, en java, le but n'est pas d'optimiser[/troll]
Tout ce qui passe pas par le port 80, c'est de la triche.

17

c'est surtout que java n'utilise pas de registres smile [/trolldefeated]

18

java utilise un processeur a pile ?
Pollux (./15) :
Euh non là pas du tout, tu confonds associativité et ordre d'évaluation : l'associativité, c'est ce qui fait que x-y-z est compris comme (x-y)-z et pas x-(y-z) ; alors que l'ordre d'évaluation, c'est ce qui fait que x+(x++) équivaut à 2*(x++) et pas à 2*(x++)+1 (en Java en tout cas, en C c'est du code invalide)


Raté :

mtrapier@prod500 ~ $ cat test.c
#include <stdio.h>

int main()
{
 int x;
 x = 1;
 printf("x=%d\n", x);
 x = x+(x++);
 printf("x=%d after [x=x+(x++)]\n", x);
 return 0;
}
mtrapier@prod500 ~ $ gcc test.c -o test.app
mtrapier@prod500 ~ $ ./test.app
x=1
x=3 after [x=x+(x++)]
mtrapier@prod500 ~ $ 
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

19

ça dépend des optimisations/compilateurs/etc

java est basé sur une pile oui.

chaque méthode a besoin d'un stack frame (qui n'a pas besoin d'être contigu au précédent), qui contient N variables locales et M places de pile.
pour faire un CALL on copie les dernieres places de la pile courante dans les variables locales d'un nouveau stack frame, puis on exécute le bytecode de la nouvelle méthode dans le frame qu'on vient de créer (je parle sans JIT et tout le bordel)

ce qui fait que le code de génération de codes d'expressions du compilo est hyper simple (parcours d'arbre en profondeur) et c'est facile de générer du code qui commence toujours par la sous-expression de gauche, et qui garantit l'ordre d'évaluation G-D

par contre en C, pour gcc je sais pas , mais en cours on a appris un algo en 2 passes et N registres, et on se démerde pour calculer d'abord la branche qui demande le moins de registres. Selon les optimisations l'ordre d'eval changera.

20

Pollux (./15) :
l'ordre d'évaluation, c'est ce qui fait que x+(x++) équivaut à 2*(x++) et pas à 2*(x++)+1 (en Java en tout cas, en C c'est du code invalide)

Mauvais example. C'est du code parfaitement valide au résultat clairement défini.
En revanche, (X++)+(X++), bien qu'étant également parfaitement valide, donne un résultat non défini.

Pour être plus précis, le C définit des "sequence points", qui sont grosso modo des barrières dans le code garantissant que tous les effets de bord précédents ont bien été pris en compte et qu'aucun des suivants ne l'a été. Entre autres éléments qui définissent un sequence point :
=> L'évaluation d'une expression complète (que ce soit un initializer, la condition d'un if/while ou simplement un wink
=> La fin de l'évaluation de l'opérande gauche des opérateurs &&, ||, ? et , (et logique, ou logique, opérateur ternaire, et virgule).
=> L'appel d'une fonction définit un sequence point après l'évaluation de tous les arguments

Pour le ./1, c'est le deuxième point qui nous intéresse, et nous garantit que l'évaluation de l'opérande de gauche du || sera toujours complète, avec tous ses effets de bord pris en compte, avant même que le code se demande s'il doit passer au côté droit.

21

intéressante, cette précision.

dans (x++)+(x++) , le problème est de savoir si le ++ sera exécuté à la fin de l'évaluation de x ou de l'expresison complète c'est ça? A mon avis il va faire

   +
  / \
 x   x
inc inc


ce qui fera
mov mem[x], r0
mov r0, r1
add #1, r0
mov r0,mem[x]
; effet de bord de x++ calculé dans r0, résultat de x++ dans r1

mov mem[x], r0
mov r0, r2
add #1, r0
mov r0,mem[x]
; effet de bord de x++ calculé dans r0, résultat de x++ dans r2

add r1, r2
; calcul de (x++) + (x++) dans r2

j'ai mal précisié mais on peut comprendre ce que je veux dire, quand même. (sinon, demandez)

enfin si je codais un compilo C, je me démerderais pour que ça génère ça oui

bref, y'a pas un sequence point après une incrémentation?

22

Vérification :

mtrapier@prod500 ~ $ cat xpp.c 
#include <stdio.h>

int main()
{
 int x, z;
 x = 1;

 printf("x=%d\n", x);

 z = (x++)+(x++);
 printf("x=%d z=%d after [z=(x++)+(x++)]\n", x, z);
 return 0;
}
mtrapier@prod500 ~ $ gcc xpp.c -o xpp.app
mtrapier@prod500 ~ $ ./xpp.app 
x=1
x=3 z=2 after [z=(x++)+(x++)]
mtrapier@prod500 ~ $ 
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

23

donc il fait 1+2 et le "++" est un sequence point top

24

En meme temps () est prioritaire sur tout, donc le premier x++ est evalué en premier, suivit par le second et enfin le x1+x2 est evalué... (en théorie) mais la ça tend a prouver que le ++ (postfixé) est evalué des que l'expression est terminé (donc apres le ";")
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

25

sans doute smile

en fait tout est défini, faut juste savoir comment grin

26

Godzil (./18) :
Pollux (./15) :
Euh non là pas du tout, tu confonds associativité et ordre d'évaluation : l'associativité, c'est ce qui fait que x-y-z est compris comme (x-y)-z et pas x-(y-z) ; alors que l'ordre d'évaluation, c'est ce qui fait que x+(x++) équivaut à 2*(x++) et pas à 2*(x++)+1 (en Java en tout cas, en C c'est du code invalide)


Raté :

mtrapier@prod500 ~ $ cat test.c
#include <stdio.h>

int main()
{
 int x;
 x = 1;
 printf("x=%d\n", x);
 x = x+(x++);
 printf("x=%d after [x=x+(x++)]\n", x);
 return 0;
}
mtrapier@prod500 ~ $ gcc test.c -o test.app
mtrapier@prod500 ~ $ ./test.app
x=1
x=3 after [x=x+(x++)]
mtrapier@prod500 ~ $ 

c'est toi le raté tongue c'est pas parce que gcc te produit un exécutable que ton code est valide...
Norme C99 :
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.

donc tu as bien une undefined behaviour ^^ ton raisonnement c'est comme si tu voyais que strlen(NULL) vaut 0 sur TI et que tu en déduisais que ça ne plante donc sur aucune plateforme...


spectras (./20) :
Pollux (./15) :
l'ordre d'évaluation, c'est ce qui fait que x+(x++) équivaut à 2*(x++) et pas à 2*(x++)+1 (en Java en tout cas, en C c'est du code invalide)

Mauvais example. C'est du code parfaitement valide au résultat clairement défini.
En revanche, (X++)+(X++), bien qu'étant également parfaitement valide, donne un résultat non défini.

Ben non, les deux sont du code invalide (enfin, invalide seulement s'il est exécuté, bien sûr), autrement dit non seulement le résultat n'est pas défini mais en plus ça peut très bien planter ^^

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

27

squalyl (./23) :
donc il fait 1+2 et le "++" est un sequence point top

non, ++ ne crée pas de sequence point... les seuls sequence points dans le programme de godzil sont les appels à printf et les ;, ce qui explique que le résultat ne soit pas défini ^^
squalyl (./25) :
sans doute smile

en fait tout est défini, faut juste savoir comment grin

peut-être que GCC adopte un comportement défini là-dessus (mais ça m'étonnerait, il peut très bien y avoir des cas où GCC fait le contraire des observations de Godzil), par contre ce qui est certain c'est que la norme ne garantit rien embarrassed

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

28

Bizzarement quand meme :

mtrapier@prod500 ~ $ cat xpp.c 
#include <stdio.h>

int main()
{
 int x, z;
 x = 1;

 printf("x=%d\n", x);

 z = (x++)+(x++);
 printf("x=%d z=%d after [z=(x++)+(x++)]\n", x, z);
 return 0;
}
mtrapier@prod500 ~ $ gcc xpp.c -o xpp.app
mtrapier@prod500 ~ $ ./xpp.app 
x=1
x=3 z=2 after [z=(x++)+(x++)]
mtrapier@prod500 ~ $ gcc xpp.c -O1 -o xpp-o1.app
mtrapier@prod500 ~ $ gcc xpp.c -O2 -o xpp-o2.app
mtrapier@prod500 ~ $ gcc xpp.c -O3 -o xpp-o3.app
mtrapier@prod500 ~ $ gcc xpp.c -Os -o xpp-os.app
mtrapier@prod500 ~ $ ./xpp-o1.app 
x=1
x=3 z=2 after [z=(x++)+(x++)]
mtrapier@prod500 ~ $ ./xpp-o2.app 
x=1
x=3 z=2 after [z=(x++)+(x++)]
mtrapier@prod500 ~ $ ./xpp-o3.app 
x=1
x=3 z=2 after [z=(x++)+(x++)]
mtrapier@prod500 ~ $ ./xpp-os.app 
x=1
x=3 z=2 after [z=(x++)+(x++)]
mtrapier@prod500 ~ $ 


Le testcase est trop simple pour etre significatif mais bon quand meme meme avec optimisation ça ne casse pas le resultat

pour rigoler :

mtrapier@prod500 ~ $ gcc xpp.c -O9 -o xpp-o9.app
mtrapier@prod500 ~ $ ./xpp-o9.app 
x=1
x=3 z=2 after [z=(x++)+(x++)]
mtrapier@prod500 ~ $ 
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

29

OK c'est pas dans la norme, mais ptet que GNU ou GCC ont ajouté des trucs pour éclaircir smile

30

squalyl> ton exemple se trouve donner ce résultat. Ca ne veut absolument pas dire qu'utilisé différememnt il aura le même comportement.
De fait, la seule garantie est celle indiquée par la norme. Tout autre code donnera un résultat indéfini (entendre par là qu'il donnera bien un résultat, mais qui peut changer selon le compilateur et la version, et que ce résultat peut potentiellement être de planter, de formater ton disque dur ou de transformer ton pc en cafetière).
Pollux (./26) :
Ben non, les deux sont du code invalide (enfin, invalide seulement s'il est exécuté, bien sûr), autrement dit non seulement le résultat n'est pas défini mais en plus ça peut très bien planter ^^

Je suis curieux de connaître ta source, parce que je vois nulle part indiqué que c'est invalide. Il est possible que ce soit un oubli, parce que pour l'opérateur d'assignation c'est bien spécifié que c'est non défini. En revanche pour l'opérateur de postincrémentation il n'y a pas de telle remarque.
[3 minutes plus tard]
Ah voilà c'est bon j'ai trouvé : "Between the previous and next sequence point an object shall have its stored value
modified at most once by the evaluation of an expression.
".
C'était dans la définition même d'une expression, et pas du côté des assignations smile

Du coup, x++ + x++ est bien illégal.
En revanche, putc(x++) || putc(x++) est légal et incrémente x une fois avant l'appel au premier putc, et une fois entre le || et l'appel au second putc.