Version longue...
Un collègue a affirmé aujourd'hui après avoir vu mon utilisation while (1)
dans un script Perl for (;;)
plus rapide. J'ai fait valoir qu'ils devraient être les mêmes en espérant que l'interprète optimiserait les différences. J'ai mis en place un script qui exécuterait 1 000 000 000 pour les itérations de boucle et le même nombre de boucles while et enregistrerait le temps entre les deux. Je n'ai trouvé aucune différence appréciable. Mon collègue a dit qu'un professeur lui avait dit que le while (1)
faisait une comparaison 1 == 1
et que for (;;)
non. Nous avons répété le même test avec le 100x le nombre d'itérations avec C ++ et la différence était négligeable. C'était cependant un exemple graphique de la rapidité avec laquelle le code compilé peut être comparé à un langage de script.
Version courte...
Y a-t-il une raison de préférer un while (1)
à un for (;;)
si vous avez besoin d'une boucle infinie pour sortir?
Remarque: si cela ne ressort pas clairement de la question. C'était purement une discussion académique amusante entre deux amis. Je suis conscient que ce n'est pas un concept très important sur lequel tous les programmeurs devraient se débattre. Merci pour toutes les bonnes réponses que j'ai (et je suis sûr que d'autres) ont appris quelques choses de cette discussion.
Mise à jour: Le collègue susmentionné a pesé avec une réponse ci-dessous.
Cité ici au cas où il serait enterré.
Il est venu d'un programmeur d'assemblage AMD. Il a déclaré que les programmeurs C (les gens) ne réalisent pas que leur code est inefficace. Il a cependant dit aujourd'hui que les compilateurs gcc sont très bons et mettent des gens comme lui à la faillite. Il a dit par exemple, et m'a parlé du
while 1
contrefor(;;)
. Je l'utilise maintenant par habitude mais gcc et surtout les interprètes feront la même opération (un saut de processeur) pour les deux ces jours, puisqu'ils sont optimisés.
la source
Réponses:
En perl, ils aboutissent aux mêmes opcodes:
De même dans GCC:
Donc, je suppose que la réponse est, ils sont les mêmes dans de nombreux compilateurs. Bien sûr, pour certains autres compilateurs, ce n'est pas nécessairement le cas, mais il y a de fortes chances que le code à l'intérieur de la boucle soit de toute façon plusieurs milliers de fois plus cher que la boucle elle-même, alors qui s'en soucie?
la source
En utilisant GCC, ils semblent tous deux compiler dans le même langage d'assemblage:
la source
Il n'y a pas beaucoup de raisons de préférer l'un à l'autre. Je pense que
while(1)
et en particulierwhile(true)
sont plus lisibles quefor(;;)
, mais c'est juste ma préférence.la source
forever
c'est son propre jeton.Il n'y a pas de différence selon la norme. 6.5.3 / 1 a:
Et le 6.5.3 / 2 a:
Donc, selon la norme C ++, le code:
est exactement le même que:
la source
Le compilateur Visual C ++ utilisé pour émettre un avertissement pour
(expression constante) mais pas pour
J'ai continué à préférer
for (;;)
pour cette raison, mais je ne sais pas si le compilateur le fait encore de nos jours.la source
for(;;)
c'est un caractère de moins à taper si l'on veut aller dans cette direction pour optimiser les choses.la source
Turbo C avec ces anciens compilateurs
for(;;)
entraîne alors un code plus rapidewhile(1)
.Aujourd'hui gcc, les compilateurs Visual C (je pense que presque tous) optimisent bien, et les processeurs avec 4,7 MHz sont rarement utilisés.
À cette époque, a
for( i=10; i; i-- )
était plus rapide quefor( i=1; i <=10; i++ )
, car compareri
est égal à 0, il en résulte un saut conditionnel CPU-Zero-Flag. Et le Zero-Flag a été modifié avec la dernière opération de décrémentation( i-- )
, aucune opération cmp supplémentaire n'est nécessaire.et ici avec
for(i=1; i<=10; i++)
avec cmpl supplémentaire:la source
Pour tous ceux qui se disputent, vous ne devriez pas utiliser des boucles while indéfinies, et suggérer des trucs stupides comme utiliser des goto ouverts (sérieusement, aïe)
Je ne peux pas vraiment être représenté d'une autre manière. Non sans créer une variable de sortie et faire de la magie noire pour la maintenir synchronisée.
Si vous avez un penchant pour la syntaxe plus goto-esque, utilisez quelque chose de sensé qui limite la portée.
En fin de compte, la vitesse n'est pas si importante
S'inquiéter de l'efficacité des différentes constructions de boucle en termes de vitesse est une perte de temps énorme. Optimisation prématurée de bout en bout. Je ne peux penser à aucune situation que j'ai jamais vue où le code de profilage a trouvé des goulots d'étranglement dans mon choix de construction de boucle.
Généralement, c'est le comment de la boucle et le quoi de la boucle.
Vous devez «optimiser» la lisibilité et la concision, et écrire ce qui est le mieux pour expliquer le problème au prochain pauvre suceur qui trouve votre code.
Si vous utilisez le truc "goto LABEL" que quelqu'un a mentionné, et que je dois utiliser votre code, soyez prêt à dormir avec un œil ouvert, surtout si vous le faites plus d'une fois, car ce genre de choses crée horriblement code spaghetti.
Ce n'est pas parce que vous pouvez créer du code spaghetti que vous devriez
la source
De Stroustrup, TC ++ PL (3e édition), §6.1.1:
Je préfère
for (;;)
.la source
Si le compilateur ne fait aucune optimisation,
for(;;)
serait toujours plus rapide quewhile(true)
. En effet, while-statement évalue la condition à chaque fois, mais for-statement est un saut inconditionnel. Mais si le compilateur optimise le flux de contrôle, il peut générer des opcodes. Vous pouvez lire le code de démontage très facilement.PS vous pourriez écrire une boucle infinie comme ceci:
la source
J'en ai entendu parler une fois.
Il est venu d'un programmeur d'assemblage AMD. Il a déclaré que les programmeurs C (les gens) ne réalisent pas que leur code est inefficace. Il a cependant dit aujourd'hui que les compilateurs gcc sont très bons et mettent des gens comme lui à la faillite. Il a dit par exemple, et m'a parlé du
while 1
contrefor(;;)
. Je l'utilise maintenant par habitude mais gcc et surtout les interprètes feront la même opération (un saut de processeur) pour les deux ces jours, puisqu'ils sont optimisés.la source
Dans une version optimisée d'un langage compilé, il ne devrait y avoir aucune différence appréciable entre les deux. Ni l'un ni l'autre ne devraient finir par effectuer des comparaisons au moment de l'exécution, ils exécuteront simplement le code de la boucle jusqu'à ce que vous quittiez manuellement la boucle (par exemple avec a
break
).la source
Je suis surpris que personne ne teste correctement
for (;;)
par rapportwhile (1)
à perl!Parce que perl est un langage interprété, le temps d'exécution d'un script perl ne comprend pas seulement la phase d'exécution (qui dans ce cas est la même) mais aussi la phase d'interprétation avant l'exécution. Ces deux phases doivent être prises en compte lors de la comparaison de vitesse.
Heureusement, perl dispose d'un module Benchmark pratique que nous pouvons utiliser pour implémenter un benchmark tel que:
Notez que je teste deux versions différentes de la boucle for infinie: une qui est plus courte que la boucle while et une autre qui a un espace supplémentaire pour lui donner la même longueur que la boucle while.
Sur Ubuntu 11.04 x86_64 avec perl 5.10.1, j'obtiens les résultats suivants:
La boucle while est clairement la gagnante sur cette plateforme.
Sur FreeBSD 8.2 x86_64 avec perl 5.14.1:
Alors que la boucle est le gagnant ici aussi.
Sur FreeBSD 8.2 i386 avec perl 5.14.1:
Étonnamment, la boucle for avec un espace supplémentaire est le choix le plus rapide ici!
Ma conclusion est que la boucle while devrait être utilisée sur la plate-forme x86_64 si le programmeur optimise la vitesse. De toute évidence, une boucle for doit être utilisée lors de l'optimisation de l'espace. Mes résultats ne sont malheureusement pas concluants par rapport aux autres plateformes.
la source
Benchmark
a ses limites et ne peut pas être utilisé pour distinguer rapide de lent si les résultats sont à moins de 7% l'un de l'autre. De plus, vous n'avez pas testé la différence entre les bouclesfor
etwhile
car chaque sous-marin le feradie
avant d'atteindre les boucles eux-mêmes. Et depuis quand la quantité d'espaces blancs importait-elle pour l'interpréteur Perl? Désolé, mais l'analyse est extrêmement imparfaite.die
est là dans mon code car mon intention est de tester uniquement le décalage horaire de compilation . Comme d'autres l'ont déjà souligné, l'octet-code résultant est identique, il est donc inutile de le tester. Étonnamment, la quantité d'espace blanc semble faire une petite différence dans ce cas dans mes environnements de test. Cela pourrait avoir quelque chose à voir avec la façon dont les personnages finissent par s'aligner dans la mémoire ou quelque chose de similaire ...Benchmark
sont pas concluants. Ne vous fiez pas du tout à cette différence de 1%!-60
exécute le test pendant 60 secondes.En théorie, un compilateur complètement naïf pourrait stocker le littéral '1' dans le binaire (gaspillage d'espace) et vérifier si 1 == 0 à chaque itération (perte de temps et plus d'espace).
En réalité, cependant, même sans optimisations, les compilateurs réduiront toujours les deux au même niveau. Ils peuvent également émettre des avertissements car cela pourrait indiquer une erreur logique. Par exemple, l'argument de
while
pourrait être défini ailleurs et vous ne réalisez pas qu'il est constant.la source
Je suis surpris que personne n'ait proposé la forme la plus directe, correspondant à l'assemblage souhaité:
la source
{ forever: do stuff; goto forever; }
)while(1)
est un idiome pourfor(;;)
reconnu par la plupart des compilateurs.J'étais heureux de voir que perl reconnaît
until(0)
aussi.la source
Pour résumer le débat
for (;;)
vswhile (1)
, il est évident que le premier était plus rapide à l'époque des anciens compilateurs non optimisateurs, c'est pourquoi vous avez tendance à le voir dans des bases de code plus anciennes telles que les commentaires de code source Lions Unix, mais à l'ère de l'optimisation badass les compilateurs ces gains sont optimisés loin du couplage qu'avec le fait que ce dernier est plus facile à comprendre que le premier, je pense qu'il serait plus préférable.la source
Je viens de tomber sur ce fil (bien que quelques années de retard).
Je pense avoir trouvé la vraie raison pour laquelle "for (;;)" est meilleur que "while (1)".
selon la "norme de codage barr 2018"
fondamentalement, ce n'est pas un problème de vitesse mais un problème de lisibilité. Selon la police / impression du code, le chiffre un (1) peut parfois ressembler à une lettre minuscule l.
soit 1 vs l. (dans certaines polices, elles semblent identiques).
Ainsi, while (1) peut ressembler à une boucle while dépendante de la lettre variable L.
while (true) peut également fonctionner mais dans certains cas plus anciens en C et en C incorporé, true / false ne sont pas encore définis à moins que stdbool.h ne soit inclus.
la source
l
, pas cela1
et qu'ellel
puisse ressembler.Je pense que les deux sont les mêmes en termes de performances. Mais je préférerais while (1) pour la lisibilité, mais je me demande pourquoi vous avez besoin d'une boucle infinie.
la source
Ce sont les mêmes. Il y a des questions beaucoup plus importantes à se poser.
Mon point qui était implicite mais pas explicitement fait ci-dessus, est qu'un compilateur décent générerait exactement le même code pour les deux formes de boucle. Le point le plus important est que la construction en boucle est une partie mineure du temps d'exécution de tout algorithme, et vous devez d'abord vous assurer que vous avez optimisé l'algorithme et tout ce qui y est lié. L'optimisation de votre construction de boucle doit absolument être au bas de votre liste de priorités.
la source