Bonjour,
Je me lance dans la programmation C et je sais que pour incrémenter une variable, on utilise i++ mais en parcourant le net, j'ai vu une autre syntaxe bizarre ++i et je me demandais à quoi ca correspondait ?
Merci
Bonjour,
Je me lance dans la programmation C et je sais que pour incrémenter une variable, on utilise i++ mais en parcourant le net, j'ai vu une autre syntaxe bizarre ++i et je me demandais à quoi ca correspondait ?
Merci
SAlut! ++i veut juste dire que la valeur de i est incrémenté avant son utilisation et i++ se sert d'abord de la valeur de i puis l'incrément ensuite. j'espère avoir pu répondre clairement . bonne suite
Un petit exemple:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 int i: i = 12; printf("i=%d\n", ++i); // affiche 13 i = 12; printf("i=%d\n", i++); // affiche 12
J'ajoute que les pré-incrémentation et pré-décrémentation existent en C depuis le début et que de nombreux langages parus depuis ne les implémentent pas, pour une raison que j'ignore.
La possibilité de faire ce genre d'opération à l'avance se justifie tout autant que celle de la mener après coup, tant d'un point de vue technique qu'algorithmique. L'exemple-ambassadeur est celui de la gestion d'une pile, structure pour le moins répandue en informatique.
- Lorsque l'on dépile, on renvoie l'objet repéré par l'index de la pile, puis on incrémente celui-ci. Donc :
- Lorsque l'on empile, il faut d'abord décrémenter l'index, puis sauver l'objet à la place nouvellement indiquée. En C, ça donnerait :
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 typedef struct _pile { char tableau [TAILLE]; unsigned int index; } pile; char depile (pile * p) { return p->tableau[p->index++]; } void empile (pile * p, char c) { p->tableau[--(p->index)] = c; }
Sans pré-décrémentation, tu serais obligé de faire l'opération d'empilement en deux étapes.
L'utilité de ces opérateurs prennent tout leur sens en C++, dans lequel on peut définir des objets conséquents répondant à ces opérateurs. Dans le cast d'une post-(in|dé)crémentation, tu es obligé de créer une copie de l'objet actuel, de le mettre à jour et de renvoyer la copie (en prenant en compte son éventuelle destruction ultérieure). En revanche, en pré-(in|dé)crémentant, il te suffit de mettre l'objet à jour puis d'y faire référence, sans avoir quoi que ce soit à déplacer.
Sur des types natifs, l'impact est négligeable, mais sur des objets plus sophistiqués, les gains en performances peuvent être spectaculaires en remplaçant simplement i++ par ++i.
Attention, on est dans un forum C donc on essaye d'oublier les concepts applicables uniquement au c++.
Je pense que Obsidian pensait à la différence de temps d'exécution entre le pre++ et le post++ (ou --, je suis pas sectaire) en C++. Le post++ demande la construction et aussi la destruction d'un objet temporaire.
Oops.
C'est bien ce que j'ai -- et d'autres -- ont tenté de mesurer dans des benchmarks. Rien de concluant à ma connaissance.Je pense que Obsidian pensait à la différence de temps d'exécution entre le pre++ et le post++ (ou --, je suis pas sectaire) en C++. Le post++ demande la construction et aussi la destruction d'un objet temporaire.
Utilisé tout seul (comme il se doit), c'est strictement pareil.
ou dans un for().
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 i++; ++i;
Ca devient tordu dans une expression. C'est tellement illisible et sujet au comportement indéterminée, que j'en déconseille l'usage dans ces conditions.
Peu de gens dans le monde sont capable de dire si i = ++i; est déterminé ou non...
Je suis 100% d'accord avec Emmanuel.
Il est tordu, et très peu lisible, de se servir de la pré-incrémentation.
Même si c'est autorisé, la lisibilité perd un tel facteur (d'autant plus que quand on trouve cela dans un code, ce n'est malheureusement pas le seul "shortcut" qui est mis), que cela amène tout droit à de l'obfuscation.
Comme l'a dit Obsidian, ce n'est pas repris par beaucoup de langages, et il ne faut pas s'en étonner.
Personellement, je déconseille fortement l'usage de la pré-incrémentation.
Personnellement - et il doit encore me manquer quelque chose (on est là, entre autre, pour apprendre de ses erreurs) -, je ne trouve pas ça plus ambigü que i = i++.
De prime abord, j'aurais même pensé que les opérateurs de pré-incrémentation et post-incrémentation étaient tous deux largement prioritaires sur =, et que la valeur de l'opérande de droite avait besoin d'être évaluée avant affectation, ne serait-ce que pour l'auto-référence style i = i + 1 puisse fonctionner. Dans ce sens, on devrait obtenir la valeur initiale de i, laquelle variable serait ensuite incrémentée implicitement, puis cette valeur initiale serait réaffectée à i, mais gcc n'est pas d'accord.
Les deux ont un comportement indefini: i est modifie deux fois sans point de sequencement entre les modifications. L'objectif profond de la regle n'est pas de simplifier le compilateur dans des cas aussi simples. C'est de permettre au compilateur de supposer i != j dans des cas comme a[i] = a[j]++.
Les priorites donnent un ordre partiel dans l'evaluation mais n'indiquent pas quand l'effet de bord des operateurs ++ et -- ou meme = a lieu. Le comportement est aussi indefini pour i = (i = 4) + 1, l'evaluation de i=4 (qui a pour resultat 4) a bien lieu avant la deuxieme assignation a i, mais cette contrainte n'existe pas pour l'effet de bord "modification de la valeur de i".
En passant, il ne s'agit pas d'une simple indetermination de l'ordre comme dans f(g(), h()); ou on sait que soit g() est appele avant h() soit h() avant g() mais qu'il n'y a pas de recouvrement. Dans
on pourrait se retrouver vraisemblablement avec t[0] qui vaut 0 sur une machine 32 bits parce que les assignations peuvent se recouvrir (partie haute de t[i], partie haute de t[j], partie basse de t[j], partie haute de t[i]).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 long long t[1]; size_t i =0, j = 0; t[i] = ( t[j] = 0xFFFFFFFFLL) + 1LL;
à compiler avec différents compilateurs, différentes options d'optimisation, sur différents CPU, …
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 #include <stdio.h> void call(int a, int b, int c, int d) { printf("%d %d %d %d ",a,b,c,d) ; } int main(int argc, char **argv) { int i = 0 ; call(i++, i++, ++i, ++i) ; printf("%d\n", i) ; i = 0 ; call(++i, ++i, i++, i++) ; printf("%d\n", i) ; return 0 ; }
et comparer avec
… surprises garanties…
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 volatile int i = 0 ;
Ça me rappelle la longue discussion avec doccpu.
Si ça intéresse, j'ai toujours les MPs qu'on s'est échangés ensuite pour clore le débat...
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager