do {…} while (false)

125

Je regardais du code par un individu et j'ai remarqué qu'il semble avoir un modèle dans ses fonctions:

<return-type> function(<params>)
{
 <initialization>

 do
 {
   <main code for function>
 }
 while(false);

 <tidy-up & return>
}

Ce n'est pas mal , c'est plus particulier (le code actuel est assez soigné et sans surprise). Ce n'est pas quelque chose que j'ai vu auparavant et je me suis demandé si quelqu'un pouvait penser à une logique derrière cela - un fond dans une langue différente peut-être?

Monsieur Boy
la source
2
Avez-vous essayé de le changer en version "normale" et de voir s'il se compile toujours? S'il ne parvient pas à se compiler lorsqu'il est écrit normalement, l'erreur du compilateur pourrait donner une idée de la raison pour laquelle cela a été fait.
Mark Byers
11
Pourquoi ne pas demander à «l'individu» plutôt que de nous demander des suppositions sur son intention?
1
Peut-être que son professeur lui a demandé d'utiliser un do...while()et il a utilisé ce code comme modèle de fonction depuis.
Hogan
6
@Neil ... Je veux éviter d'avoir l'air idiot quand je le confronte et qu'il explique l'utilisation du C ++ super avancé auquel je n'ai jamais pensé.
M. Boy
6
Il semble y avoir déjà pas mal de réponses différentes, pouvez-vous demander à l'auteur original quelles étaient ses intentions et poster en retour?
nevets1219

Réponses:

175

Vous pouvez breaksortir de do{...}while(false).

Thomas Eding
la source
95
+1 parce que c'est probablement l'intention du code, mais faire quelque chose comme ça est juste un goto idiot déguisé. Si vous pensez qu'un goto est le bon outil pour le travail, alors vous devriez simplement utiliser un # $ (* # @ goto.
dsimcha
56
C'est plus qu'un goto déguisé. C'est un goto restreint (structuré).
Thomas Eding
19
De quelle manière est-il «restreint»? Seul sauter en avant n'est guère une "restriction". Un goto est un goto, et en habiller un pour donner l'impression que ce n'est pas un est pire que de simplement utiliser un goto en premier lieu.
Anon.
45
@Anon: sauter en avant est une restriction sur un goto, et sauter en dehors est définitivement une restriction. Le vrai problème avec les gotos est le code spaghetti, et un saut en avant et en arrière limite considérablement.
David Thornley
33
Une boucle réelle n'est pas sémantiquement un goto. Un conditionnel n'est pas sémantiquement un goto. "Aller à la fin de la fonction et faire le code de nettoyage" est sémantiquement un goto. Utilisez des gotos lorsque la sémantique s'applique, n'habillez pas quelque chose de sémantiquement différent parce que vous en avez peur.
Anon.
126

Beaucoup de gens soulignent qu'il est souvent utilisé avec break comme une manière maladroite d'écrire "goto". C'est probablement vrai s'il est écrit directement dans la fonction.

Dans une macro, OTOH, do { something; } while (false)est un moyen pratique de FORCER un point-virgule après l'appel de la macro, absolument aucun autre jeton n'est autorisé à suivre.

Et une autre possibilité est qu'il y ait eu une boucle là-bas ou qu'une itération devrait être ajoutée dans le futur (par exemple dans le développement piloté par les tests, l'itération n'était pas nécessaire pour passer les tests, mais logiquement, il serait logique de faire une boucle là-bas si la fonction devait être un peu plus générale que ce qui est actuellement requis)

Ben Voigt
la source
18
+1 pour mentionner l'utilité de ceci dans les macros; Je suis surpris que personne d'autre n'ait mentionné cela!
Nick Meyer
7
Oui, la macro est en fait une utilisation parfaitement valable de cela. Bien sûr, en dehors des macros, c'est juste idiot ...;)
jalf
12
Ce n'est pas gênant, c'est utile, car c'est un goto à portée - cela signifie que toutes les variables que vous déclarez dans la boucle do sont détruites, alors que le goto ne le fait pas.
Ana Betts
9
@Paul: Rien ne vous empêche d'ajouter des accolades autour d'un tas d'instructions pour forcer ce comportement avec goto.
erikkallen
5
@Paul: sortir d'un bloc provoque très certainement la destruction des variables locales en C ++, comme break. Et en C, les variables ne sont pas vraiment détruites, leur espace de pile est simplement récupéré.
Ben Voigt
25

La pause comme goto est probablement la réponse, mais je vais avancer une autre idée.

Peut-être qu'il voulait avoir une variable définie localement et a utilisé cette construction pour obtenir une nouvelle portée.

Rappelez-vous que si le C ++ récent permet {...}n'importe où, ce n'était pas toujours le cas.

Hogan
la source
30
Il aurait pu simplement utiliser des accolades dans ce cas.
Nemanja Trifunovic
2
@Nemanja, vous seriez surpris de voir combien de développeurs ne le savent pas et essayez quelque chose en rapport avec ce que suggère Hogan
Polaris878
8
@Polaris @Nemanja, ce n'est pas jusqu'à ce que j'avais programmé en C / C ++ comme 4 ans que j'ai compris que vous pouvez créer une nouvelle portée locale {} n'importe où . C'est particulièrement pratique dans le switch-casecode
Earlz
1
@Nemanja: Je ne sais pas exactement quand, mais je suis sûr que {...}n'importe où est un développement plus moderne en C ++ (rappelez-vous que le premier C ++ que j'ai utilisé a été implémenté avec un pré-processeur et qui ne permettait pas cette utilisation moderne.) l'auteur était juste une vieille école.
Hogan
2
Quand n'a-t-il pas permis d'utiliser des accolades partout? J'ai commencé à programmer comme il y a 15 ans, et c'était autorisé à l'époque (à la fois dans mon manuel et dans chaque compilateur que j'ai essayé).
erikkallen
20

Je l'ai vu utilisé comme un modèle utile lorsqu'il existe de nombreux points de sortie potentiels pour la fonction, mais le même code de nettoyage est toujours requis quelle que soit la façon dont la fonction se termine.

Cela peut rendre un arbre if / else-if fastidieux beaucoup plus facile à lire, en ayant simplement à casser chaque fois qu'un point de sortie est atteint, avec le reste de la logique en ligne par la suite.

Ce modèle est également utile dans les langages qui n'ont pas d'instruction goto. C'est peut-être là que le programmeur d'origine a appris le modèle.

Cameron
la source
15
Ensuite, utilisez simplement un goto honnête et simple au lieu d'un goto à peine déguisé.
dsimcha
4
J'aime mieux cette façon. Il est facile à lire et ne porte pas la stigmatisation d'un goto.
Cameron
8
Les gotos sont parfaitement faciles à lire s'ils sont utilisés avec parcimonie et localement. Ils ont eu leur stigmatisation à l'époque où ils étaient la principale forme de contrôle de flux et sautaient à travers des centaines de lignes.
dsimcha
13
Ne pas utiliser goto à cause d'une «stigmatisation» est un signe certain d'une programmation culte du cargo.
Anon.
6
Sans oublier qu'une masse de code de nettoyage est une mauvaise odeur. Ceci étant C ++, le code de nettoyage doit normalement être dans des destructeurs appelés pendant le traitement RAII.
David Thornley
12

J'ai vu du code comme celui-là pour que vous puissiez l'utiliser breaken quelque gotosorte.

Brian Young
la source
10

Ceci est juste une perversion de whilepour obtenir la sématique de goto tidy-upsans utiliser le mot goto.

Il est mauvaise forme parce que lorsque vous utilisez d' autres boucles dans la partie extérieure whiledu breaksdevenir ambigu au lecteur. "Est-ce que c'est censé sortir? Ou est-ce uniquement destiné à sortir de la boucle intérieure?"

John Knoeller
la source
10

Je pense qu'il est plus pratique d'écrire breakau lieu de goto end. Vous n'avez même pas besoin de trouver un nom pour l'étiquette qui rend l'intention plus claire: vous ne voulez pas sauter à une étiquette avec un nom spécifique. Tu veux sortir d'ici.

Il y a également de fortes chances que vous ayez besoin des accolades de toute façon. Voici donc la do{...}while(false);version:

do {
   // code
   if (condition) break; // or continue
   // more code
} while(false);

Et c'est ainsi qu'il vous faudrait l'exprimer si vous vouliez utiliser goto:

{
   // code
   if (condition) goto end;
   // more code
}
end:

Je pense que la signification de la première version est beaucoup plus facile à saisir. De plus, il est plus facile d'écrire, plus facile à étendre, plus facile à traduire dans une langue qui ne prend pas en charge goto, etc.


La préoccupation la plus fréquemment mentionnée à propos de l'utilisation de breakest qu'il est mal déguisé goto. Mais a en breakfait plus de ressemblance avec return: Les deux instructions sortent d'un bloc de code qui est à peu près structuré par rapport à goto. Néanmoins, les deux instructions autorisent plusieurs points de sortie dans un bloc de code, ce qui peut parfois prêter à confusion. Après tout, j'essaierais d'opter pour la solution la plus claire, quelle que soit la situation spécifique.

Robert
la source
Oh, j'ai juste remarqué que je ne comprenais pas complètement la question avant de répondre. Je pensais qu'il s'agissait de l'utilisation de do{ ... }while(false);en général. Mais en fait, il s'agit de l'utiliser pour émuler une sorte de try{ ... }finally{ ... }.
Robert
Belle observation du parallèle entre pause et retour plutôt que goto. Convenez que la solution la plus claire est la meilleure. Dans de nombreux cas, il est probablement plus clair d'encapsuler du code comme celui-ci dans sa propre fonction distincte qui utilise return plutôt que break, puis de faire le nettoyage dans la fonction appelante.
persiflage
7

Cette astuce est utilisée par les programmeurs qui sont trop timides pour utiliser un explicite gotodans leur code. L'auteur du code ci-dessus voulait avoir la possibilité de sauter directement au point "nettoyage et retour" à partir du milieu du code. Mais ils ne voulaient pas utiliser d'étiquette et explicite goto. Au lieu de cela, ils peuvent utiliser un breakà l'intérieur du corps du cycle «faux» ci-dessus pour obtenir le même effet.

Fourmi
la source
7

C'est une pratique très courante. En C . J'essaie d'y penser comme si vous vouliez vous mentir d' une manière "je n'utilise pas un goto". En y réfléchissant, il n'y aurait rien de mal à une gotoutilisation similaire. En fait, cela réduirait également le niveau d'indentation.

Cela dit, cependant, j'ai remarqué que très souvent ces do..whileboucles ont tendance à se développer. Et puis ils obtiennent des ifs et des elses à l'intérieur, ce qui rend le code en fait pas très lisible, encore moins testable.

Ceux-ci do..whilesont normalement destinés à faire un nettoyage . Par tous les moyens possibles, je préférerais utiliser RAII et revenir tôt d'une fonction courte . D'un autre côté, C ne vous offre pas autant de commodités que C ++ , ce qui en fait l'une do..whiledes meilleures approches pour effectuer un nettoyage.

Dmitry
la source
6

Cela ressemble à un programmeur C. En C ++, les variables automatiques ont des destructeurs que vous utilisez pour nettoyer, il ne devrait donc y avoir rien à nettoyer avant le retour. En C, vous n'aviez pas cet idiome RAII , donc si vous avez un code de nettoyage commun, vous l' gotoutilisez ou utilisez une boucle à passage unique comme ci-dessus.

Son principal inconvénient par rapport à l'idiome C ++ est qu'il ne sera pas rangé si une exception est levée dans le corps. C n'avait pas d'exceptions, donc ce n'était pas un problème, mais cela en fait une mauvaise habitude en C ++.

Pete Kirkham
la source
4

Plusieurs explications. Le premier est général, le second est spécifique aux macros de préprocesseur C avec des paramètres:

Contrôle de flux

J'ai vu cela utilisé dans du code C brut. Fondamentalement, c'est une version plus sûre de goto, car vous pouvez en sortir et toute la mémoire est nettoyée correctement.

Pourquoi quelque chose gotocomme ça serait bien? Eh bien, si vous avez du code où à peu près chaque ligne peut retourner une erreur, mais vous devez réagir à tous de la même façon (par exemple , en remettant l'erreur à votre correspondant après le nettoyage), il est généralement plus facile à lire pour éviter un if( error ) { /* cleanup and error string generation and return here */ }comme cela évite la duplication du code de nettoyage.

Cependant, en C ++, vous avez des exceptions + RAII exactement dans ce but, donc je considérerais que c'est un mauvais style de codage.

Vérification des points-virgules

Si vous oubliez le point-virgule après un appel de macro de type fonction, les arguments peuvent se contracter d'une manière indésirable et se compiler dans une syntaxe valide. Imaginez la macro

#define PRINT_IF_DEBUGMODE_ON(msg) if( gDebugModeOn ) printf("foo");

C'est accidentellement appelé comme

if( foo )
    PRINT_IF_DEBUGMODE_ON("Hullo\n")
else
    doSomethingElse();

Le "else" sera considéré comme étant associé au gDebugModeOn, alors quand fooc'est le cas false, l'inverse exact de ce qui était prévu se produira.

Fournir une portée pour les variables temporaires.

Puisque le do / while a des accolades, les variables temporaires ont une portée clairement définie à laquelle elles ne peuvent pas échapper.

Éviter les avertissements de type "point-virgule éventuellement indésirable"

Certaines macros ne sont activées que dans les versions de débogage. Vous les définissez comme:

#if DEBUG
#define DBG_PRINT_NUM(n) printf("%d\n",n);
#else
#define DBG_PRINT_NUM(n) 
#endif

Maintenant, si vous utilisez ceci dans une version de version à l'intérieur d'un conditionnel, il se compile en

if( foo )
    ;

De nombreux compilateurs voient cela comme

if( foo );

Ce qui est souvent écrit accidentellement. Vous recevez donc un avertissement. Le do {} while (false) cache cela au compilateur et est accepté par lui comme une indication que vous ne voulez vraiment rien faire ici.

Éviter la capture de lignes par des conditions

Macro de l'exemple précédent:

if( foo )
    DBG_PRINT_NUM(42)
doSomething();

Maintenant, dans une version de débogage, puisque nous incluons aussi habituellement le point-virgule, cela compile très bien. Cependant, dans la version de version, cela se transforme soudainement en:

if( foo )

doSomething();

Ou plus clairement formaté

if( foo )
    doSomething();

Ce qui n'est pas du tout ce qui était prévu. L'ajout d'un do {...} while (false) autour de la macro transforme le point-virgule manquant en une erreur de compilation.

Qu'est-ce que cela signifie pour l'OP?

En général, vous souhaitez utiliser des exceptions en C ++ pour la gestion des erreurs et des modèles au lieu de macros. Cependant, dans le cas très rare où vous avez encore besoin de macros (par exemple, lorsque vous générez des noms de classe en utilisant le collage de jetons) ou que vous êtes limité au C pur, c'est un modèle utile.

uliwitness
la source
En ce qui concerne la portée, vous n'avez pas besoin de l'appareil de boucle; un bloc « sans fioritures » est légal: x =1; y = 2; { int tmp = y; y = x; x = tmp; }.
chepner
Un bloc sans ornement n'impose cependant pas la présence d'un point-virgule manquant, ce qui pourrait avoir des effets secondaires indésirables. Faire pendant(); REQUIERT le point-virgule et donc, par exemple, ne provoque pas le dessin des instructions suivantes dans un "si" si la macro ne définit rien dans une version de version, comme mon exemple ci-dessus.
uliwitness
Cela ne pourrait-il pas être évité en fournissant simplement une meilleure définition de la macro? #define DBG_PRINT_NUM(n) {}.
chepner
1
Non, car {} est une instruction complète, c'est-à-dire équivalente à un ";". Donc, si vous écrivez, if(a) DBG_PRINT_NUM(n); else other();il ne se compilera pas. Seul if(a) {} else other();ou if(a) ; else other();est valide, mais if(a) {}; else other();ne l'est pas, car cela fait que la clause "if" se compose de deux instructions.
uliwitness
2

Peut-être qu'il est utilisé pour breakpouvoir être utilisé à l'intérieur pour abandonner l'exécution de code supplémentaire à tout moment:

do {
    if (!condition1) break;
    some_code;
    if (!condition2) break;
    some_further_code;
    // …
} while(false);
Gombo
la source
7
Cela semble être une tentative d'éviter d'utiliser gotosimplement parce que quelqu'un a entendu dire que c'était «mauvais».
Anon.
1
Peut-être, mais C ++ a des exceptions pour cette raison même.
TED
2

Je pense que cela est fait pour utiliser breakou des continuedéclarations. Une sorte de logique de code "goto".

Ivan Nevostruev
la source
2

C'est simple: apparemment, vous pouvez sortir de la fausse boucle à tout moment en utilisant l' breakinstruction. En outre, le dobloc est une portée distincte (qui pourrait également être réalisée { ... }uniquement avec ).

Dans une telle situation, il peut être préférable d'utiliser RAII (les objets se détruisant automatiquement correctement lorsque la fonction se termine). Une autre construction similaire est l'utilisation de goto- oui, je sais que c'est mal , mais il peut être utilisé pour avoir un code de nettoyage commun comme ceci:

<return-type> function(<params>)
{
 <initialization>

 <main code for function using "goto error;" if something goes wrong>

 <tidy-up in success case & return>

 error:

 <commmon tidy-up actions for error case & return error code or throw exception>
}

(En aparté: la construction do-while-false est utilisée dans Lua pour trouver l' continueinstruction manquante .)

AndiDog
la source
2

De nombreux répondants en ont donné la raison do{(...)break;}while(false). Je voudrais compléter l'image par un autre exemple concret.

Dans le code suivant, j'ai dû définir l'énumérateur en operationfonction de l'adresse pointée par le datapointeur. Parce qu'un boîtier de commutation ne peut être utilisé que sur des types scalaires, je l'ai fait de cette façon de manière inefficace

if (data == &array[o1])
    operation = O1;
else if (data == &array[o2])
    operation = O2;
else if (data == &array[on])
    operation = ON;

Log("operation:",operation);

Mais puisque Log () et le reste du code se répètent pour toute valeur d'opération choisie, je me demandais comment ignorer le reste des comparaisons lorsque l'adresse a déjà été découverte. Et c'est là que cela est do{(...)break;}while(false)utile.

do {
    if (data == &array[o1]) {
        operation = O1;
        break;
    }
    if (data == &array[o2]) {
        operation = O2;
        break;
    }
    if (data == &array[on]) {
        operation = ON;
        break;
    }
} while (false);

Log("operation:",operation);

On peut se demander pourquoi il ne pouvait pas faire la même chose avec breakune ifdéclaration, comme:

if (data == &array[o1])
{
    operation = O1;
    break;
}
else if (...)

breakinteragit uniquement avec le plus proche englobante boucle ou d'un commutateur, que ce soit un for, whileou le do .. whiletype, donc , malheureusement , cela ne fonctionnera pas.

4pie0
la source
1

Quel âge avait l'auteur?

Je demande parce que je suis tombé une fois sur un code Fortran en temps réel qui faisait cela, à la fin des années 80. Il s'avère que c'est un très bon moyen de simuler des threads sur un système d'exploitation qui ne les a pas. Il vous suffit de mettre tout le programme (votre planificateur) dans une boucle et d'appeler vos "routines de thread" une par une. Les routines de thread elles-mêmes sont des boucles qui itèrent jusqu'à ce que l'une des conditions se produise (souvent l'une étant une certaine quantité de le temps est passé). Il s'agit d'un "multitâche coopératif", en ce sens qu'il appartient aux threads individuels d'abandonner le processeur de temps en temps pour que les autres ne soient pas affamés. Vous pouvez imbriquer les appels de sous-programme en boucle pour simuler la priorité des threads bandes.

TED
la source
0

Je suis d'accord avec la plupart des affiches sur l'utilisation comme un goto à peine déguisé. Les macros ont également été mentionnées comme une motivation potentielle pour écrire du code dans le style.

J'ai également vu cette construction utilisée dans les environnements mixtes C / C ++ comme une exception pour les pauvres. Le "do {} while (false)" avec un "break" peut être utilisé pour passer à la fin du bloc de code si quelque chose qui justifierait normalement une exception se produisait dans la boucle.

J'ai également ressenti cette construction utilisée dans les magasins où l'idéologie du «rendement unique par fonction» est appliquée. Encore une fois, cela remplace un "goto" explicite - mais la motivation est d'éviter de multiples points de retour, pas de "sauter" du code et de continuer l'exécution réelle dans cette fonction.

Stan Graves
la source
0

Je travaille avec Adobe InDesign SDK, et les exemples du SDK InDesign ont presque toutes les fonctions écrites comme ça. Cela est dû au fait que les fonctions sont généralement très longues. Où vous devez faire QueryInterface (...) pour obtenir quoi que ce soit du modèle objet de l'application. Donc, généralement, chaque QueryInterface est suivie de ifpas bien, pause.

Kugel
la source
0

Beaucoup ont déjà indiqué la similitude entre cette construction et a goto, et ont exprimé une préférence pour le goto. Peut-être que les antécédents de cette personne comprenaient un environnement où les goto étaient strictement interdits par les directives de codage?

Mark Ransom
la source
0

L'autre raison à laquelle je peux penser est qu'il décore les accolades, alors que je crois que dans un nouveau standard C ++, les accolades nues ne sont pas correctes (ISO C ne les aime pas). Sinon pour calmer un analyseur statique comme des peluches.

Vous ne savez pas pourquoi vous les voulez, peut-être une portée variable ou un avantage avec un débogueur.

Voir la boucle Trivial Do While et les accolades sont bonnes à partir de C2.

Pour clarifier ma terminologie (qui, je crois, suit l'utilisation standard):

Bretelles nues :

init();
...
{
c = NULL;
mkwidget(&c);
finishwidget(&c);
}
shutdown();

Accolades vides (NOP):

{}

par exemple

while (1)
   {}  /* Do nothing, endless loop */

Bloquer :

if (finished)
{
     closewindows(&windows);
     freememory(&cache);
}

qui deviendrait

if (finished)
     closewindows(&windows);
freememory(&cache);

si les accolades sont supprimées, modifiant ainsi le flux d'exécution, pas seulement la portée des variables locales. Donc pas «autonome» ou «nu».

Des accolades nues ou un bloc peuvent être utilisés pour signifier toute section de code qui pourrait être un potentiel pour une fonction (en ligne) que vous souhaitez marquer, mais pas refactoriser à ce moment-là.

mctylr
la source
Vraiment? C'est une honte. L'une des rares choses que j'ai aimées à propos de C était qu'il vous permettait de déclarer une nouvelle portée imbriquée à peu près n'importe où.
TED
1
Les accolades nues sont parfois utiles pour corriger les accidents étranges. Voir blogs.msdn.com/oldnewthing/archive/2004/05/20/135841.aspx .
Brian
1
En C ++, un bloc (c'est-à-dire vos "accolades nues") peut être utilisé partout où une seule instruction serait autorisée.
Ben Voigt
@BenVoigt Accolades vides c'est-à-dire qu'un NOP est différent d'un "accolades nues" qui est un bloc ajouté autour d'une séquence linéaire d'instructions. Par exemple, `printf (" Bonjour "); {putchar (','); putchar (0x20); } printf ("world! \ n"); `où les accolades ne font pas partie du contrôle de boucle ou de branche.
mctylr
@mctylr: Je ne parlais pas d'accolades vides.
Ben Voigt
0

C'est un moyen artificiel d'émuler un GOTOcar ces deux sont pratiquement identiques:

// NOTE: This is discouraged!
do {
    if (someCondition) break;
    // some code be here
} while (false);
// more code be here

et:

// NOTE: This is discouraged, too!
if (someCondition) goto marker;
// some code be here
marker:
// more code be here

D'un autre côté, les deux devraient vraiment être faits avec ifs:

if (!someCondition) {
    // some code be here
}
// more code be here

Bien que l'imbrication puisse devenir un peu moche si vous transformez simplement une longue chaîne de forward- GOTOs en ifs imbriqués . La vraie réponse est une refactorisation appropriée, cependant, sans imiter les constructions de langage archaïques.

Si vous essayiez désespérément de translittérer un algorithme contenant GOTOs, vous pourriez probablement le faire avec cet idiome. Ce n'est certainement pas standard et c'est un bon indicateur du fait que vous n'adhérez pas étroitement aux idiomes attendus de la langue.

Je ne connais aucun langage de type C où do / while est une solution idiomatique pour quoi que ce soit, en fait.

Vous pourriez probablement refactoriser tout le désordre en quelque chose de plus sensé pour le rendre plus idiomatique et beaucoup plus lisible.

Alan Plum
la source
1
Alan, ce do..while(false)n'est pas pour exécuter un nombre de fois "indéfini", c'est pour exécuter une fois .
Dmitry
2
Il s'exécute un nombre indéfini de fois si vous avez une continueinstruction conditionnelle à la fin, comme je l'ai montré. Par undefinedje veux simplement dire que vous ne savez pas s'il s'exécute plus d'une fois, sauf si vous pouvez prédire si les conditions seront remplies à une itération spécifique. Sans aucun continues, do..while(false)fonctionnera une fois, mais aussi sans aucun breaks, while(true)fonctionnera pour toujours, donc le «comportement par défaut» n'est pas vraiment pertinent pour comprendre ce qui peut être fait avec les boucles.
Alan Plum
C'est utile lorsque vous définissez une macro qui a plusieurs instructions. Si vous les encapsulez dans un do / while (false), vous pouvez utiliser la macro dans une instruction if / else comme tout autre appel de fonction. voir noveltheory.com/TechPapers/ While.htm pour une explication
John Paquin
5
Quelqu'un ne comprend pas la sémantique de continue. continuene répète PAS la boucle. "L' continueinstruction doit se produire uniquement dans une instruction d'itération et fait passer le contrôle à la partie de continuation de boucle de la plus petite instruction d' itération englobante , c'est-à-dire à la fin de la boucle."
Ben Voigt
-1, les deux premières déclarations ne sont pas identiques pour les raisons que @BenVoigt souligne.
cmh
0

Certains codeurs préfèrent n'avoir qu'une seule sortie / retour de leurs fonctions. L'utilisation d'un mannequin do {....} while (false); vous permet de "sortir" de la boucle factice une fois que vous avez terminé et que vous avez toujours un seul retour.

Je suis un codeur Java, donc mon exemple serait quelque chose comme

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class p45
{
    static List<String> cakeNames = Arrays.asList("schwarzwald torte", "princess", "icecream");
    static Set<Integer> forbidden = Stream.of(0, 2).collect(Collectors.toSet());

    public static  void main(String[] argv)
    {
        for (int i = 0; i < 4; i++)
        {
            System.out.println(String.format("cake(%d)=\"%s\"", i, describeCake(i)));
        }
    }


    static String describeCake(int typeOfCake)
    {
        String result = "unknown";
        do {
            // ensure type of cake is valid
            if (typeOfCake < 0 || typeOfCake >= cakeNames.size()) break;

            if (forbidden.contains(typeOfCake)) {
                result = "not for you!!";
                break;
            }

            result = cakeNames.get(typeOfCake);
        } while (false);
        return result;
    }
}
David Young
la source
0

Dans de tels cas, j'utilise

switch(true) {
   case condution1:
      ...
      break;
   case condution2:
      ...
      break;
}
Женя Остроушко
la source
-1

C'est amusant. Il y a probablement des ruptures à l'intérieur de la boucle comme d'autres l'ont dit. Je l'aurais fait de cette façon:

while(true)
{
   <main code for function>
   break; // at the end.
}
fastcodejava
la source
2
Avec un potentiel de bouclage pour toujours? do..while(false)sort toujours, while(true)est plus risqué.
Dmitry
1
while(true)est l'idiome correct dans la plupart des langues. Vous le trouverez souvent dans les applications GUI en tant que boucle principale du programme. Parce que vous supposez fondamentalement que le programme ne devrait pas mourir tant qu'on ne lui a pas dit de le faire, do..while(false)cela provoquerait toutes sortes de logiques artificielles. Cette approche peut être plus risquée à partir d'un point de vue perfectionniste, mais elle est sémantiquement plus facile et donc moins sujette aux erreurs pour les programmeurs humains (désolé, Skynet).
Alan Plum
2
@dmitry do{...}while(false)est exactement le même quewhile(true){ .. break;}
N 1.1
4
@ N1.1: Pas en présence de continue, ils ne sont pas les mêmes.
Ben Voigt