53 votes

Raisons techniques du formatage lors de l'incrémentation par 1 dans une boucle 'for' ?

Partout sur le web, des échantillons de code ont for qui ressemblent à ceci :

for(int i = 0; i < 5; i++)

alors que j'ai utilisé le format suivant :

for(int i = 0; i != 5; ++i)

Je le fais parce que je pense que c'est plus efficace, mais est-ce vraiment important dans la plupart des cas ?

20 votes

Je dirais que pour la plupart des compilateurs et des processeurs, votre boucle n'est pas plus rapide du tout. Utilisez la première version pour que les autres programmeurs puissent comprendre la boucle plus facilement. Maintenant, en comptant jusqu'à zéro sera vous aider sur certains processeurs, mais vous devez vous demander si cela en vaut la peine.

2 votes

Quelle est la raison pour laquelle vous pensez qu'il est plus efficace ? Vous parlez en termes de temps de fonctionnement, n'est-ce pas ?

0 votes

Oui, courir serait plus rapide je crois mais je peux me tromper.

86voto

Lucas Points 5723

Tout le monde aime ses micro-optimisations, mais cela ne ferait pas de différence à mon avis. J'ai compilé les deux variantes avec g++ on pour les processeurs Intel sans aucune optimisation fantaisiste et les résultats sont les suivants

for(int i = 0; i < 5; i++)
    movl $0, -12(%ebp)
    jmp L2
L3:
    leal    -12(%ebp), %eax
    incl    (%eax)
L2:
    cmpl    $4, -12(%ebp)
    jle L3

for(int i = 0; i != 5; ++i)
    movl    $0, -12(%ebp)
    jmp L7
L8:
    leal    -12(%ebp), %eax
    incl    (%eax)
L7:
    cmpl    $5, -12(%ebp)
    jne L8

Creo que jle y jne devrait se traduire par des instructions aussi rapides sur la plupart des architectures. Donc, pour les performances, vous ne devriez pas faire de distinction entre les deux. En général, je suis d'accord pour dire que la première est un peu plus sûre et je pense aussi qu'elle est plus courante.


EDIT (2 ans plus tard) : Étant donné que ce fil de discussion a de nouveau reçu beaucoup d'attention récemment, je voudrais ajouter qu'il sera difficile de répondre à cette question de manière générale. Les versions du code qui sont les plus efficaces ne sont pas spécifiquement définies par la norme Norme C [PDF] (il en va de même pour le C++ et probablement aussi pour le C#).

Section 5.1.2.3 Exécution du programme

§1 Les descriptions sémantiques de la présente Norme internationale décrivent le comportement d'une machine abstraite dans laquelle les questions d'optimisation ne sont pas pertinentes.

Mais il est raisonnable de supposer qu'un compilateur moderne produira un code tout aussi efficace et je pense que dans de très rares cas seulement le loop-test y el expression de comptage être le goulot d'étranglement d'une boucle for.

Quant au goût, j'écris

for(int i = 0; i < 5; ++i)

0 votes

@harryovers : Je dois dire que je ne serais pas confus par votre façon de faire. Je pense que ce qui se passe est assez évident, mais vous ne devriez pas vous énerver pour de petites optimisations, si vous n'avez pas de problème de performance.

0 votes

Je ne suis pas vraiment inquiet à ce sujet, je voulais juste savoir ce que les gens en pensaient.

6 votes

La partie importante de ceci est que le x86 utilise un registre de code de condition, donc il calcule à la fois les drapeaux d'égalité et de signe pour toute comparaison, donc les sauts conditionnels pour toutes les entrées/égalités intégrales prennent exactement le même temps.

69voto

Yuriy Faktorovich Points 33347

Si pour une raison quelconque i saute à 50 dans la boucle, votre version bouclerait indéfiniment. Le site i < 5 est un contrôle de bon sens.

18 votes

Si i est modifié dans la boucle, les choses sont suffisamment mauvaises pour que je doive probablement plutôt ont une boucle infinie pour m'aider à trouver ce qui se passe. Sérieusement, si quelque chose joue avec i, il devrait y avoir un assert dans la boucle pour le découvrir. Une autre raison pour laquelle je préfère les langages qui me laissent faire un foreach au lieu d'un for quand c'est possible.

0 votes

Est-ce vraiment si grave ? Et si quelqu'un veut sortir de la boucle après qu'elle soit terminée ? Définir i à int.MaxValue ferait l'affaire sans remaniement.

12 votes

Comment sortir de la boucle ? Ugh. Si rupture ne fonctionne pas pour faire cela, refactor !

41voto

Tomek Szpakowicz Points 5340

Le formulaire

for (int i = 0; i < 5; i++)

est idiomatique Il est donc plus facile à lire pour les programmeurs C expérimentés. Surtout lorsqu'il est utilisé pour itérer sur un tableau. Vous devriez écrire du code idiomatique autant que possible car il se lit plus rapidement.

Il est également un peu plus sûr dans les situations où vous modifiez i à l'intérieur de la boucle ou utilisez un incrément différent de 1. Mais c'est une chose mineure. Il est préférable de concevoir soigneusement votre boucle et d'ajouter des assertions pour détecter rapidement les hypothèses brisées.

13 votes

Le formulaire for (int i = 0; i != 5; ++i) serait plus idiomatique pour un grand nombre d'utilisateurs de C++. En réalité, je ne vois pas comment on pourrait dire que l'un ou l'autre n'est pas idiomatique dans un langage de type C, ce sont tous deux des trucs à genoux dans tous ces langages.

0 votes

@JonHanna En ce qui concerne la deuxième partie de votre commentaire : J'ai appris le C chez K&R et c'est la version que j'ai vu depuis être la plus utilisée. Et je la trouve la plus lisible en un coup d'œil. Quant à la première partie : Voulez-vous dire que la boucle for avec les itérateurs C++ ressemble à ceci : for (some::long_iter_type it = begin; it != end; ++it) ... ? Si c'est le cas, alors : a) Nous parlons de code C, principalement. b) Même en C++. int i n'est pas un itérateur.

2 votes

Nous ne parlons pas de code C, la question inclut explicitement C++ et C# et implicitement Java et Javascript. Les entiers ne sont pas des itérateurs, mais leur utilisation peut conduire à ce que != soit plus instinctif que <. Je ne peux toujours pas considérer l'un ou l'autre comme plus idiomatique dans l'un ou l'autre de ces langages, ce sont toutes des formes pour lesquelles vous devriez les comprendre comme naturelles dans chacun de ces langages.

18voto

Chris Ballance Points 17329

Si la règle d'incrémentation change légèrement, vous avez immédiatement une boucle infinie. Je préfère de loin la première condition finale.

7 votes

Vrai. Aller à i+=2 dans l'exemple conduit à la douleur.

13voto

Mark Points 21191

Cela dépend de la langue.

Les textes C++ suggèrent souvent le deuxième format, car il fonctionne avec les itérateurs qui peuvent être comparés (!=) directement, mais pas avec une condition supérieure ou inférieure. De plus, le préincrément peut être plus rapide que le postincrément car il n'est pas nécessaire d'avoir une copie de la variable pour la comparaison - cependant les optimiseurs peuvent s'occuper de cela.

Pour les entiers, les deux formes fonctionnent. L'idiome courant pour le C est la première forme, tandis que pour le C++, c'est la seconde.

Pour une utilisation en C# et Java, j'utiliserais foreach pour boucler sur tous les éléments.

En C++, il y a aussi la fonction std::for_each qui nécessite l'utilisation d'un foncteur et qui, dans les cas simples, est probablement plus complexe que l'un ou l'autre des exemples présentés ici, ainsi que la fonction Boost FOR_EACH qui peut ressembler à la fonction foreach du C# mais qui est complexe à l'intérieur.

0 votes

Bien que je sois d'accord, le PO essaie de micro-optimiser en distinguant une != et un < donc je doute qu'ils veuillent introduire la surcharge d'un itérateur pour un appel foreach !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X