for (;;) {
//Something to be done repeatedly
}
J'ai vu ce genre de chose beaucoup utilisé, mais je pense que c'est plutôt étrange ... Ne serait-il pas beaucoup plus clair de dire while(true)
, ou quelque chose du genre?
Je suppose que (comme c'est la raison pour laquelle beaucoup de programmeurs ont recours à du code cryptique), c'est une toute petite marge plus rapide?
Pourquoi, et est-ce vraiment la peine? Si oui, pourquoi ne pas simplement le définir de cette façon:
#define while(true) for(;;)
Je préfère for(;;)
pour deux raisons.
La première est que certains compilateurs produisent des avertissements sur while(true)
(quelque chose comme "la condition de boucle est constante"). Éviter les avertissements est toujours une bonne chose à faire.
Un autre est que je pense que for(;;)
est plus clair et plus révélateur. Je veux une boucle infinie. Il n'a littéralement a aucune condition, cela ne dépend de rien. Je veux juste que ça continue pour toujours, jusqu'à ce que je fasse quelque chose pour en sortir.
Alors qu'avec while(true)
, eh bien, qu'est-ce qui a vraiment à voir avec quoi que ce soit? Je ne suis pas intéressé à boucler jusqu'à ce que true devienne faux, c'est ce que cette forme dit littéralement (boucle alors que true est vrai). Je veux juste faire une boucle.
Et non, il n'y a absolument aucune différence de performances.
Personnellement, j'utilise for (;;)
car il n'y a pas de chiffres, c'est juste un mot-clé. Je le préfère à while (true)
, while (1)
, while (42)
, while (!0)
etc etc.
À cause de Dennis Ritchie
J'ai commencé à utiliser for (;;)
parce que c'est ainsi que Dennis Ritchie le fait dans K&R, et lorsque j'apprends une nouvelle langue, j'essaie toujours d'imiter les gars intelligents.
C'est du C/C++ idiomatique. Il est probablement préférable à long terme de s'y habituer si vous prévoyez d'en faire beaucoup dans l'espace C/C++.
Votre #define
ne fonctionnera pas, car la chose en cours de définition doit ressembler à un identifiant C.
Tous les compilateurs modernes généreront le même code pour les deux constructions.
Ce n'est certainement pas plus rapide dans aucun compilateur sensé. Ils seront tous deux compilés en sauts inconditionnels. La version for est plus facile à taper (comme l'a dit Neil) et sera claire si vous comprenez la syntaxe de boucle.
Si vous êtes curieux, voici ce que gcc 4.4.1 me donne pour x86. Les deux utilisent l'instruction x86 JMP .
void while_infinite()
{
while(1)
{
puts("while");
}
}
void for_infinite()
{
for(;;)
{
puts("for");
}
}
compile (en partie):
.LC0:
.string "while"
.text
.globl while_infinite
.type while_infinite, @function
while_infinite:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
.L2:
movl $.LC0, (%esp)
call puts
jmp .L2
.size while_infinite, .-while_infinite
.section .rodata
.LC1:
.string "for"
.text
.globl for_infinite
.type for_infinite, @function
for_infinite:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
.L5:
movl $.LC1, (%esp)
call puts
jmp .L5
.size for_infinite, .-for_infinite
Je préfère for (;;)
car c'est le plus cohérent dans différents langages de type C.
En C++ while (true)
est très bien, mais en C vous dépendez d'un en-tête pour définir true
, mais TRUE
est aussi une macro couramment utilisée. Si vous utilisez while (1)
c'est correct en C et C++ et JavaScript, mais pas Java ou C #, qui nécessitent que la condition de boucle soit booléenne, comme while (true)
ou while (1 == 1)
. En PHP, les mots-clés sont insensibles à la casse mais le langage préfère la majuscule TRUE
.
Cependant, for (;;)
est toujours complètement correct dans toutes ces langues.
Personnellement, je préfère l'idiome for (;;)
(qui sera compilé dans le même code que while (TRUE)
.
L'utilisation de while (TRUE)
peut être plus lisible dans un sens, j'ai décidé d'utiliser l'idiome for (;;)
parce que il se démarque.
Une construction de boucle infinie devrait être facilement remarquée ou appelée dans le code, et je pense personnellement que le style for (;;)
le fait un peu mieux que while (TRUE)
ou while (1)
.
Je rappelle également que certains compilateurs émettent des avertissements lorsque l'expression de contrôle d'une boucle while est une constante. Je ne pense pas que cela arrive trop, mais juste le potentiel d'avertissements fallacieux me suffit pour vouloir l'éviter.
J'ai vu que certaines personnes le préfèrent parce qu'elles ont un #define quelque part comme ceci:
#define EVER ;;
Ce qui leur permet d'écrire ceci:
for (EVER)
{
/* blah */
}
Qu'en est-il (si votre langue le prend en charge):
start:
/* BLAH */
goto start;
Il n'y a aucune différence en termes de code machine généré.
Cependant, pour inverser la tendance, je dirais que la forme while (TRUE) est beaucoup plus lisible et intuitive que pour (;;), et que la lisibilité et la clarté sont des raisons beaucoup plus importantes pour les directives de codage que toutes les raisons pour lesquelles je '' J'ai entendu parler de l'approche for (;;) (je préfère baser mes directives de codage sur un raisonnement solide et/ou une preuve d'efficacité moi-même).
Pas seulement un modèle bien connu, mais un idiome standard en C (et C++)
Les deux doivent être identiques si votre code est optimisé par le compilateur. Pour expliquer ce que je veux dire par optimisation, voici un exemple de code écrit en MSVC 10:
int x = 0;
while(true) // for(;;)
{
x +=1;
printf("%d", x);
}
Si vous le construisez en mode Debug (sans aucune optimisation (/ Od)) le démontage montre la nette différence. Il y a des instructions supplémentaires pour la condition true
dans while
.
while(true)
00D313A5 mov eax,1 //extra
00D313AA test eax,eax //extra
00D313AC je main+39h (0D313B9h) //extra
{
x +=1;
00D313AE mov eax,dword ptr [x]
00D313B1 add eax,1
00D313B4 mov dword ptr [x],eax
printf("%d", x);
...
}
00D313B7 jmp main+25h (0D313A5h)
for(;;)
{
x +=1;
00D213A5 mov eax,dword ptr [x]
00D213A8 add eax,1
00D213AB mov dword ptr [x],eax
printf("%d", x);
...
}
00D213AE jmp main+25h (0D213A5h)
Cependant, si vous construisez votre code en mode Release (avec par défaut Maximize Speed (/ O2)) vous obtenez la même sortie pour les deux. Les deux boucles sont réduites à une instruction de saut.
for(;;)
{
x +=1;
01291010 inc esi
printf("%d", x);
...
}
0129101C jmp main+10h (1291010h)
while(true)
{
x +=1;
00311010 inc esi
printf("%d", x);
...
}
0031101C jmp main+10h (311010h)
Celui que vous utiliserez n'a pas d'importance pour un compilateur décent avec optimisation de la vitesse activée.
while(true)
génère un avertissement avec Visual Studio (la condition est constante). La plupart des endroits où j'ai travaillé compilent des builds de production avec des avertissements en tant qu'erreurs. Alors
for(;;)
est préféré.
C'est une question de préférence personnelle qui est plus rapide. Personnellement, je suis un touchtypist et ne regarde jamais mon clavier pendant la programmation - je peux taper les 104 touches de mon clavier.
Je trouve si plus rapide de taper "while (TRUE)".
J'ai mentalement ajouté quelques mesures de mouvement des doigts et les ai totalisées. "for (;;)" a environ 12 largeurs de touches de mouvements vers l'arrière et la quatrième (entre les touches home et les touches, et entre les touches home et la touche MAJ) "tandis que (TRUE)" a environ 14 largeurs de clés de mouvements vers l'arrière et Quatrième.
Cependant, je suis beaucoup moins sujet aux erreurs lorsque je tape ce dernier. Je pense mentalement avec des mots à la fois, donc je trouve plus rapide de taper des choses comme "nIndex" que des acronymes tels que "nIdx" car je dois épeler mentalement le lettrage plutôt que de le dire dans mon esprit et laisser mes doigts s'auto -tapez le mot (comme faire du vélo)
(Mon benchmark TypingTest.com = 136 WPM)
Toutes les bonnes réponses - le comportement doit être exactement le même.
CEPENDANT - Supposons simplement que cela DID fait une différence. Supposons que l'un d'eux prenne 3 instructions supplémentaires par itération.
Devriez-vous vous en soucier?
UNIQUEMENT si ce que vous faites à l'intérieur de la boucle est presque rien, ce qui est presque jamais le cas.
Mon point est qu'il y a une micro-optimisation et une macro-optimisation. La micro-optimisation, c'est comme "se faire couper les cheveux pour perdre du poids".
Je ne peux pas imaginer qu'un compilateur utile génère un code différent. Même si c'était le cas, il n'y aurait aucun moyen de déterminer sans tester le compilateur particulier qui était plus efficace.
Cependant, je vous suggère de préférer for(;;)
pour les raisons suivantes:
un certain nombre de compilateurs que j'ai utilisés génèrent un avertissement d'expression constante pendant tout (vrai) avec les paramètres de niveau d'avertissement appropriés.
dans votre exemple, la macro TRUE peut ne pas être définie comme vous vous y attendez
il existe de nombreuses variantes possibles de la boucle while infinie telles que while(1)
, while(true)
, while(1==1)
etc; donc for(;;)
est susceptible d'entraîner une plus grande cohérence.
for(;;Sleep(50))
{
// Lots of code
}
Est plus clair que:
while(true)
{
// Lots of code
Sleep(50);
}
Cela ne s'applique pas si vous n'utilisez pas Sleep()
.
La boucle "forever" est populaire dans les systèmes embarqués comme boucle d'arrière-plan. Certaines personnes l'implémentent comme:
for (; ;)
{
// Stuff done in background loop
}
Et parfois, il est implémenté comme:
while (TRUE /* or use 1 */)
{
// Stuff done in background loop
}
Et encore une autre implémentation est:
do
{
// Stuff done in background loop
} while (1 /* or TRUE */);
Un compilateur d'optimisation doit générer le code d'assemblage identique ou similaire pour ces fragments. Une remarque importante: le temps d'exécution des boucles n'est pas un gros problème car ces boucles durent indéfiniment et plus de temps est consacré à la section de traitement.
Je suppose que tandis que (true) est plus lisible que pour (;;) - son aspect comme programmeur manque quelque chose dans la boucle for :)
et qui se soucie lequel est le plus rapide le cas échéant
La raison la plus importante d'utiliser "for (;;)" est la peur d'utiliser "while (TRUE)" lorsque vous effectuez une programmation exploratoire. Il est plus facile de contrôler la quantité de répétitions avec "pour", et aussi, de convertir la boucle "pour" en infini.
Par exemple, si vous construisez une fonction récursive, vous pouvez limiter la quantité d'appels à la fonction avant de la convertir en boucle infinie.
for(int i=0;i<1000;i++) recursiveFunction(oneParam);
Quand je suis sûr de ma fonction, je la convertis en boucle infinie:
for(;;) recursiveFunction(oneParam);