Quelle est la difference entre le post incrémentation et le pré incrémentation?
et a quel moment l'utilser? Comment cela fonction?et merci
Quelle est la difference entre le post incrémentation et le pré incrémentation?
et a quel moment l'utilser? Comment cela fonction?et merci
La différence, c'est que la "post" incrémentation ne retourne pas la même valeur que la pré-incrémentation:
Naturellement, quand on met i++ ou ++i tout seul, on s'en moque puisqu'on n'utilise pas la valeur de retour.
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 void UneFonction(void) { int i=5, j=5; int a = i++; int b = ++j; /* Ici, i et j valent tous les deux 6. Par contre, a vaut 5 et b vaut 6. */ }
En C++, un moyen de de définir la post-incrémentation est dire qu'elle retourne une copie de l'ancienne valeur.
je vais t'expliquer ca avec des exemple
1.post-incrementation
---------------------
donnera comme resultat
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 j=10; i=j++; //post-incrementation
i=10;
j=11;
parceque l'incrementation se fait aprés l'affectation (post)
2.pré-incrementation
--------------------
donnera comme resultat
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 j=10; i=++j; //pré-incrementation
i=11:
j=11;
parceque l'incrementation se fait avant l'affectation (pré)
3.Melange des deux
-------------------
donnera comme resultat
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 j=10; k=11; i=(j++)+(++k);
i=22;
parce que l'incrementation de j se fait aprés l'affectation et
l'incrementation de k se fait avant l'affectation
j=11;
k=12;
on peut dire que ce code est equivalent au precedent
j'espere que ca va t'aider sinon jette un coup d'oeil a la faq http://cpp.developpez.com/faq/cpp/
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 j=10; k=11; k=k+1; //pré-incrementaiton de k i=j+k; j=j+1; //post-incrementation de j
Je rebondis un peu sur ce (très) vieux sujet... J'ai fait quelques recherches sur le sujet et je lis plusieurs sons de cloche.
Pour ce qui est de quand c'est incrémenté ou pas, y'a pas de soucis, tout est clair. Ma question concerne plutôt la "performance". Y'a-t-il un réel intérêt à écrire :
plutôt que :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 for (int i = 0; i < 42; ++i) { ... }
Le résultat sera évidemment le même mais est-ce que celà change quelques chose pour le compilateur? Et si oui, est-ce vrai pour tous les types (par exemple sur des itérateurs)?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 for (int i = 0; i < 42; i++) { ... }
En théorie, le code sera le même pour un int, à moins d'avoir un compilateur débile.
Pour un itérateur, je dirais qu'il faut un vachement bon optimiseur, et que c'est pratiquement mort si le code de l'opérateur ++ postfixe n'est pas connu (ce qui n'est jamais le cas pour un itérateur template).
Pour tous les types natifs (les int dans ton cas), je doute qu'il y ait un compilateur qui produise un code inefficace dans les cas de post incrémentation. Pareil pour les pointeurs... (Medinoc, je ne crois pas que cela pose un problème sur les itérateurs sur types de base ou POD, parce que ce sont, en principe, l'équivalent strict de pointeurs. En fait, si le problème existait, ce serait, pour moi, au moins, une raison de préférer les pointeurs aux itérateurs, car cela reviendrait à dire que le compilateur n'arrive pas à optimiser du code contenant des itérateurs)
Maintenant, sur des types utilisateur, ou n'importe quoi d'un peu compliqué, rien n'est garanti. En gros, si ton type est assez simple, le compilateur arrivera à voir que les variables qu'il sauvegarde ne servent à rien, et les éliminera à l'optimisation, s'il est plus compliqué, ca peut ne pas marcher.
Maintenant une boucle comme
serait probablement de toutes façons atrocement inefficace. Donc je ne crois pas qu'il y ait un risque à toujours utiliser la post incrémentation dans les boucles...
Code : Sélectionner tout - Visualiser dans une fenêtre à part for(TMonType t=montypedep;t!=montypefin;t++)
En résumé, je pense que c'est un faux problème.
Francois
Dernière modification par Invité ; 17/07/2009 à 15h46.
Ok! Merci bien pour vos réponses.
En fait, il m'avait sembler entendre (tout ça reste très vague ) qu'à la compilation et/ou l'execution, la pré-incrémenation avait des avantages en terme de performance...
Encore une fois, c'est juste la lecture de ce vieux post qui m'a mis le doute et je voulais juste avoir l'avis d'autres.
C'est probablement une autre (très) fausse idée reçue!
Non ce n'est pas nécessairement une fausse idée, mais comme expliqué par Médinoc et fcharton, c'est à voir au cas par cas.
Pour les types primitifs (int, size_t, etc.) et pour les pointeurs sur un compilateur décent, il n'y aura pas d'impact.
Par contre sur des types plus complexe, il va y avoir création d'un objet temporaire lors de la post-incrémetation qui va forcément couté à l'exécution donc il y aura bien un impact et il faut donc préféré la pré-incrémentation.
Sur des compilateurs très ancien, particulièrement peu efficace voire sur certains compilateurs avec 0 optimisation il est possible d'observer également le phénomène sur des types primitifs.
Tout ça en partant du principe que les surcharges des opérateurs de pré-incrémentation et de post-incrémentation ont bien le sens habituel.
Ok, merci bien!
Donc, à la limite, dans le doute, il vaut peut-être mieux prendre l'habitude de la pré-incrémentation (là où il n'y a pas d'affectation j'entend)...
Oui, dans le doute, il vaut toujours mieux faire ++p que p++. L'habitude d'écrire i++ dans les boucles est cependant très répandue (personnellement, je n'arrive pas à m'en défaire), il est donc utile de savoir que ce n'est pas grave...
Pour les types utilisateurs, comme le disait gl, il faut se méfier des opérateurs, qui peuvent avoir été redéfinis... Personnellement, dans le doute, je fais p+=1 ou même p=p+1.
Francois
Grain de sel : théoriquement, la pré-incrémentation est plus efficace car il n'est pas nécessaire de conserver l'ancienne valeur (=une copie, même si c'est de registre à registre) pour effectuer l'action... La post-incrémentation, elle, requiert cette copie, donc coûte plus en temps CPU.
Ceci étant dit :
- La plupart des compilateurs C/C++ transforment automatiquement un "i++" en "++i" lorsque la valeur de retour n'est pas utilisée, y compris en debug (sans optimisations donc). Si des optimisations sont requises pour activer ce point, c'est toujours actif dès le premier niveau d'optimisation.
- Seuls de très vieux compilateurs sont impactés par ce phénomène : si tu n'utilises que des compilateurs récents, ce sera transparent dans l'écriture classique d'une boucle.
- Il est bien entendu évident que cette transformation automatique n'est jamais appliquée lorsque la valeur de retour est utilisée...
- Le problème de redéfinition des opérateurs n'existant qu'en C++, il n'est pas utile de se préoccuper de ce point particulier si tu ne travailles qu'en C. En C++, c'est autre chose, il faut savoir exactement sur quoi on travaille pour ne pas faire d'erreurs.
C'est vieux... je sais ...
Je m'ennuyais et un collègue me prenait la tête là-dessus, j'ai suivi la discussion ici, et ouf en lisant le dernier, enfin quelqu'un qui connaît LA réponse ... je cherchais à prouver à mon collègue que j'avais raison (faut toujours gonfler les muscles pour se faire entendre).
C'est un peu plus compliqué que ça : prises au sein d'un programme C, ces constructions du langage n'ont pas d'équivalent direct en instructions machine. « Transformer i++ en ++i » n'a pas de sens. Le compilateur génèrera le code le plus rapide avec le comportement escompté en fonction du contexte.
Ce dont tu peux convaincre ton collègue en revanche, c'est que le code généré est le même en comparant les sorties assembleur (-S pour GCC) de deux programmes utilisant respectivement l'une et l'autre des expressions.
Attention, ça n'est vrai que si i est un scalaire où il est évident que l'on souhaite incrémenter la valeur. S'il s'agit d'un type utilisateur ou d'un itérateur. On a dû définir deux fonctions différentes, le compilateur va donc utiliser la bonne (il n'a pas à prendre d'initiative). Et il est possible qu'après optimisation cela revienne au même, mais pas toujours.
C'est pourquoi en C++, il vaut mieux s'habituer à utiliser la pré-incrémentation si on ne s'intéresse pas à la valeur de retour.
En C, on peut écrire n'importe laquelle car l'opération n'existe que sur des scalaires.
oui c'est justement sur ce point que j'insistais, qu'il fallait que ça devienne presque un automatisme... la + part du temps, les codeurs peu expérimentés n'utilisent pas la valeur de retour de la post-incrémentation.
ceci dit, il est vrai que je parlais du C++ ... j'aurais dû préciser
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