Ich habe mir einen Code von einer Person angesehen und festgestellt, dass er ein Muster in seinen Funktionen zu haben scheint:
<return-type> function(<params>)
{
<initialization>
do
{
<main code for function>
}
while(false);
<tidy-up & return>
}
Es ist nicht schlecht , eigentümlicher (der eigentliche Code ist ziemlich ordentlich und nicht überraschend). Das habe ich noch nie gesehen und ich habe mich gefragt, ob sich jemand eine Logik dahinter vorstellen kann - Hintergrund vielleicht in einer anderen Sprache?
do...while()
und seitdem hat er diesen Code als Funktionsvorlage verwendet.Antworten:
Sie können
break
ausdo{...}while(false)
.quelle
Viele Leute weisen darauf hin, dass es oft mit Pause als unangenehme Art des Schreibens von "goto" verwendet wird. Das ist wahrscheinlich wahr, wenn es direkt in die Funktion geschrieben ist.
In einem Makro ist OTOH
do { something; } while (false)
eine bequeme Möglichkeit, ein Semikolon nach dem Makroaufruf zu erzwingen. Es darf absolut kein anderes Token folgen.Eine andere Möglichkeit besteht darin, dass dort entweder einmal eine Schleife vorhanden war oder dass in Zukunft eine Iteration hinzugefügt werden soll (z. B. in der testgetriebenen Entwicklung war keine Iteration erforderlich, um die Tests zu bestehen, aber logischerweise wäre es sinnvoll, dort eine Schleife durchzuführen, wenn Die Funktion musste etwas allgemeiner sein als derzeit erforderlich.
quelle
Die Pause als goto ist wahrscheinlich die Antwort, aber ich werde eine andere Idee vorbringen.
Vielleicht wollte er lokal definierte Variablen haben und benutzte dieses Konstrukt, um einen neuen Bereich zu erhalten.
Denken Sie daran
{...}
, dass dies in C ++ zwar überall möglich ist, dies jedoch nicht immer der Fall war.quelle
{}
überall einen neuen lokalen Bereich erstellen können . Dies ist besonders praktisch imswitch-case
Code{...}
irgendwo eine modernere Entwicklung in C ++ ist (denken Sie daran, dass das erste C ++, das ich verwendet habe, mit einem Vorprozessor implementiert wurde und diese moderne Verwendung nicht zuließ.) Vielleicht Der Autor war einfach so altmodisch.Ich habe gesehen, dass es als nützliches Muster verwendet wird, wenn es viele potenzielle Austrittspunkte für die Funktion gibt, aber immer der gleiche Bereinigungscode erforderlich ist, unabhängig davon, wie die Funktion beendet wird.
Es kann einen lästigen if / else-if-Baum viel einfacher zu lesen machen, indem es einfach brechen muss, wenn ein Austrittspunkt erreicht wird, und der Rest der Logik anschließend inline ist.
Dieses Muster ist auch in Sprachen nützlich, die keine goto-Anweisung haben. Vielleicht hat der ursprüngliche Programmierer dort das Muster gelernt.
quelle
Ich habe solchen Code gesehen, damit Sie ihn
break
als einegoto
Art verwenden können.quelle
Dies ist nur eine Perversion von
while
, um die Sematik zu erhalten,goto tidy-up
ohne das Wort goto zu verwenden.Es ist schlechter Stil, weil wenn Sie andere Schleifen innerhalb des äußeren
while
derbreaks
den Leser zweideutig worden. "Soll das zum Ausgang gehen? Oder soll das nur aus der inneren Schleife ausbrechen?"quelle
Ich denke , es ist bequemer zu schreiben
break
stattgoto end
. Sie müssen sich nicht einmal einen Namen für das Etikett ausdenken, was die Absicht klarer macht: Sie möchten nicht zu einem Etikett mit einem bestimmten Namen springen. Du willst hier raus.Es besteht auch die Möglichkeit, dass Sie die Zahnspange sowieso benötigen. Das ist also die
do{...}while(false);
Version:Und so müssten Sie es ausdrücken, wenn Sie Folgendes verwenden möchten
goto
:Ich denke, die Bedeutung der ersten Version ist viel einfacher zu verstehen. Außerdem ist es einfacher zu schreiben, einfacher zu erweitern, einfacher in eine Sprache zu übersetzen, die nicht unterstützt
goto
wird usw.Die am häufigsten erwähnte Sorge über die Verwendung von
break
ist, dass es eine schlecht getarnte istgoto
. Hat aber tatsächlichbreak
mehr Ähnlichkeit mitreturn
: Beide Anweisungen springen aus einem Codeblock, der im Vergleich zu ziemlich strukturiert istgoto
. Trotzdem erlauben beide Anweisungen mehrere Austrittspunkte in einem Codeblock, was manchmal verwirrend sein kann. Immerhin würde ich versuchen, die klarste Lösung zu finden, was auch immer das in der spezifischen Situation ist.quelle
do{ ... }while(false);
im Allgemeinen. Aber eigentlich geht es darum, damit eine Art zu emulierentry{ ... }finally{ ... }
.Dieser Trick wird von Programmierern verwendet, die zu schüchtern sind, um einen expliziten
goto
Code zu verwenden. Der Autor des obigen Codes wollte die Möglichkeit haben, direkt von der Mitte des Codes zum Punkt "Bereinigen und Zurückgeben" zu springen. Aber sie wollten kein Etikett verwenden und explizitgoto
. Stattdessen können sie einenbreak
im Körper des obigen "falschen" Zyklus verwenden, um den gleichen Effekt zu erzielen.quelle
Es ist eine sehr verbreitete Praxis. In C . Ich versuche es mir so vorzustellen, als ob du dich selbst belügen willst, "ich benutze kein
goto
". Wenn man darüber nachdenkt, wäre an einemgoto
ähnlichen Gebrauch nichts auszusetzen . Tatsächlich würde dies auch die Einrückungsstufe verringern.Ich bemerkte jedoch, dass diese
do..while
Schleifen sehr oft wachsen. Und dann bekommen sieif
s undelse
s hinein und machen den Code tatsächlich nicht sehr lesbar, geschweige denn testbar.Diese
do..while
sind normalerweise für eine Bereinigung vorgesehen . Auf jeden Fall würde ich es vorziehen, RAII zu verwenden und frühzeitig von einer kurzen Funktion zurückzukehren. Auf der anderen Seite bietet C Ihnen nicht so viele Annehmlichkeiten wie C ++ , was einendo..while
der besten Ansätze für eine Bereinigung darstellt.quelle
Es sieht aus wie ein C-Programmierer. In C ++ verfügen automatische Variablen über Destruktoren, die Sie zum Bereinigen verwenden. Daher sollte vor der Rückgabe nichts aufgeräumt werden müssen. In C hatten Sie dieses RAII- Idiom nicht. Wenn Sie also allgemeinen Bereinigungscode haben, haben Sie es auch
goto
oder verwenden Sie eine Durchlaufschleife wie oben.Sein Hauptnachteil gegenüber der C ++ - Sprache ist, dass es nicht aufräumt, wenn eine Ausnahme in den Körper geworfen wird. C hatte keine Ausnahmen, daher war dies kein Problem, aber es macht es zu einer schlechten Angewohnheit in C ++.
quelle
Mehrere Erklärungen. Der erste ist allgemein, der zweite ist spezifisch für C-Präprozessor-Makros mit folgenden Parametern:
Ablaufsteuerung
Ich habe gesehen, dass dies in einfachem C-Code verwendet wird. Grundsätzlich ist es eine sicherere Version von goto, da Sie daraus ausbrechen können und der gesamte Speicher ordnungsgemäß bereinigt wird.
Warum sollte so etwas
goto
gut sein? Wenn Sie einen Code haben, in dem so gut wie jede Zeile einen Fehler zurückgeben kann, Sie jedoch auf alle gleich reagieren müssen (z. B. indem Sie den Fehler nach der Bereinigung Ihrem Anrufer übergeben), ist dies normalerweise besser lesbar, um einen Fehler zu vermeidenif( error ) { /* cleanup and error string generation and return here */ }
als Es vermeidet das Duplizieren von Bereinigungscode.In C ++ gibt es jedoch Ausnahmen + RAII für genau diesen Zweck, daher würde ich es als schlechten Codierungsstil betrachten.
Semikolonprüfung
Wenn Sie das Semikolon nach einem funktionsähnlichen Makroaufruf vergessen, werden Argumente möglicherweise unerwünscht kontrahiert und in eine gültige Syntax kompiliert. Stellen Sie sich das Makro vor
Das nennt man versehentlich als
Das "else" wird als mit dem verknüpft betrachtet
gDebugModeOn
, also wannfoo
istfalse
, geschieht genau das Gegenteil von dem, was beabsichtigt war.Bereitstellung eines Bereichs für temporäre Variablen.
Da das do / while geschweifte Klammern hat, haben temporäre Variablen einen klar definierten Bereich, dem sie nicht entkommen können.
Vermeiden Sie "möglicherweise unerwünschte Semikolon" -Warnungen
Einige Makros werden nur in Debug-Builds aktiviert. Sie definieren sie wie folgt:
Wenn Sie dies nun in einem Release-Build innerhalb einer Bedingung verwenden, wird es kompiliert
Viele Compiler sehen dies als dasselbe an wie
Was oft versehentlich geschrieben wird. Sie erhalten also eine Warnung. Das do {} while (false) verbirgt dies vor dem Compiler und wird von ihm als Hinweis darauf akzeptiert, dass Sie es wirklich sind nichts tun möchten.
Vermeiden der Erfassung von Linien durch Bedingungen
Makro aus vorherigem Beispiel:
In einem Debug-Build wird dies nun problemlos kompiliert, da wir gewöhnlich auch das Semikolon eingefügt haben. Im Release-Build wird daraus jedoch plötzlich:
Oder klarer formatiert
Welches ist überhaupt nicht das, was beabsichtigt war. Durch Hinzufügen eines do {...} while (false) um das Makro wird das fehlende Semikolon in einen Kompilierungsfehler umgewandelt.
Was bedeutet das für das OP?
Im Allgemeinen möchten Sie Ausnahmen in C ++ für die Fehlerbehandlung und Vorlagen anstelle von Makros verwenden. In dem sehr seltenen Fall, in dem Sie noch Makros benötigen (z. B. beim Generieren von Klassennamen mithilfe des Einfügens von Token) oder auf einfaches C beschränkt sind, ist dies ein nützliches Muster.
quelle
x =1; y = 2; { int tmp = y; y = x; x = tmp; }
.#define DBG_PRINT_NUM(n) {}
.if(a) DBG_PRINT_NUM(n); else other();
wird es nicht kompiliert. Nurif(a) {} else other();
oderif(a) ; else other();
ist gültig, aberif(a) {}; else other();
nicht, da die "if" -Klausel dadurch aus zwei Anweisungen besteht.Vielleicht wird es verwendet, damit
break
es im Inneren verwendet werden kann, um die Ausführung von weiterem Code jederzeit abzubrechen:quelle
goto
nur weil jemand gehört hat, dass es "schlecht" ist.Ich denke, dies wird getan, um
break
odercontinue
Aussagen zu verwenden. Eine Art "goto" -Codelogik.quelle
Es ist ganz einfach: Anscheinend können Sie mit der
break
Anweisung jederzeit aus der gefälschten Schleife springen . Darüber hinaus ist derdo
Block ein separater Bereich (der auch nur mit erreicht werden könnte{ ... }
).In einer solchen Situation ist es möglicherweise besser, RAII zu verwenden (Objekte, die automatisch automatisch zerstört werden, wenn die Funktion endet). Ein anderes ähnliches Konstrukt ist die Verwendung von
goto
- ja, ich weiß, dass es böse ist , aber es kann verwendet werden, um allgemeinen Bereinigungscode wie folgt zu haben:(Nebenbei: Das Konstrukt do-while-false wird in Lua verwendet, um die fehlende
continue
Anweisung zu ermitteln.)quelle
Viele Antwortende gaben den Grund dafür an
do{(...)break;}while(false)
. Ich möchte das Bild durch ein weiteres Beispiel aus der Praxis ergänzen.Im folgenden Code musste ich den Enumerator
operation
basierend auf der Adresse festlegen , auf die derdata
Zeiger zeigt. Da ein Switch-Case zunächst nur für Skalartypen verwendet werden kann, habe ich dies auf diese Weise ineffizient durchgeführtDa sich Log () und der Rest des Codes für einen beliebigen Operationswert wiederholen, habe ich mir überlegt, wie ich den Rest der Vergleiche überspringen kann, wenn die Adresse bereits gefunden wurde. Und hier
do{(...)break;}while(false)
kommt es zum Einsatz.Man mag sich fragen, warum er
break
in einerif
Aussage nicht dasselbe tun konnte , wie:break
wirkt ausschließlich mit der nächsten einschließenden Schleife oder Schaltern, ob es eine seinfor
,while
oderdo .. while
Art, so dass leider nicht funktionieren.quelle
Wie alt war der Autor?
Ich frage, weil ich in den späten 80ern einmal auf einen Echtzeit-Fortran-Code gestoßen bin, der das getan hat. Es stellt sich heraus, dass dies eine wirklich gute Möglichkeit ist, Threads auf einem Betriebssystem zu simulieren, auf dem sie nicht vorhanden sind. Sie setzen einfach das gesamte Programm (Ihren Scheduler) in eine Schleife und rufen Ihre "Thread" -Routinen nacheinander auf. Die Thread-Routinen selbst sind Schleifen, die iterieren, bis eine von mehreren Bedingungen eintritt (häufig eine bestimmte Menge von Zeit ist vergangen). Es ist "kooperatives Multitasking", da es an den einzelnen Threads liegt, die CPU von Zeit zu Zeit aufzugeben, damit die anderen nicht verhungern. Sie können die Schleifen-Unterprogrammaufrufe verschachteln, um die Thread-Priorität zu simulieren Bands.
quelle
Zusätzlich zu den bereits erwähnten 'goto-Beispielen' wird manchmal die Redewendung do ... while (0) in einer Makrodefinition verwendet, um Klammern in der Definition bereitzustellen, und der Compiler arbeitet weiterhin mit dem Hinzufügen eines Semikolons am Ende von ein Makroaufruf.
http://groups.google.com/group/comp.soft-sys.ace/browse_thread/thread/52f670f1292f30a4?tvc=2&q=while+(0)
quelle
Ich stimme den meisten Postern hinsichtlich der Verwendung als dünn getarntes Goto zu. Makros wurden auch als mögliche Motivation für das Schreiben von Code im Stil erwähnt.
Ich habe dieses Konstrukt auch in gemischten C / C ++ - Umgebungen als Ausnahme eines armen Mannes gesehen. Das "do {} while (false)" mit einem "break" kann verwendet werden, um zum Ende des Codeblocks zu springen, falls in der Schleife etwas auftritt, das normalerweise eine Ausnahme rechtfertigt.
Ich habe dieses Konstrukt auch in Geschäften verwendet, in denen die Ideologie "Single Return per Function" durchgesetzt wird. Dies ist wiederum anstelle eines expliziten "goto" - aber die Motivation besteht darin, mehrere Rückgabepunkte zu vermeiden, den Code nicht zu "überspringen" und die tatsächliche Ausführung innerhalb dieser Funktion fortzusetzen.
quelle
Ich arbeite mit Adobe InDesign SDK, und in den InDesign SDK-Beispielen ist fast jede Funktion so geschrieben. Es liegt an der Tatsache, dass die Funktionen normalerweise sehr lang sind. Wo Sie QueryInterface (...) ausführen müssen, um etwas aus dem Anwendungsobjektmodell abzurufen. Also normalerweise folgt auf jedes QueryInterface
if
nicht gut gelaufen , Pause.quelle
Viele haben bereits die Ähnlichkeit zwischen diesem Konstrukt und a angegeben
goto
und eine Präferenz für das goto zum Ausdruck gebracht. Vielleicht beinhaltete der Hintergrund dieser Person eine Umgebung, in der Gotos durch Codierungsrichtlinien strengstens verboten waren?quelle
Der andere Grund, an den ich denken kann, ist, dass es die Zahnspangen verziert , während ich glaube, dass nackte Zahnspangen mit einem neueren C ++ - Standard nicht in Ordnung sind (ISO C mag sie nicht). Ansonsten einen statischen Analysator wie Flusen zu beruhigen.
Sie sind sich nicht sicher, warum Sie sie möchten, möglicherweise einen variablen Bereich oder einen Vorteil mit einem Debugger.
Siehe Trivial Do While-Schleife , und Klammern sind ab C2 gut.
Um meine Terminologie zu verdeutlichen (von der ich glaube, dass sie der Standardverwendung folgt):
Nackte Zahnspangen :
Leere Zahnspangen (NOP):
z.B
Block :
das würde werden
Wenn die geschweiften Klammern entfernt werden, ändert sich nicht nur der Umfang lokaler Variablen, sondern auch der Ausführungsfluss. Also nicht "freistehend" oder "nackt".
Nackte Klammern oder ein Block können verwendet werden, um jeden Codeabschnitt zu kennzeichnen, der möglicherweise für eine (Inline-) Funktion geeignet ist, die Sie markieren möchten, aber zu diesem Zeitpunkt nicht umgestalten.
quelle
Es ist eine erfundene Art, a zu emulieren,
GOTO
da diese beiden praktisch identisch sind:und:
Auf der anderen Seite sollten beide wirklich mit
if
s gemacht werden:Obwohl die Verschachtelung etwas hässlich werden kann, wenn Sie nur eine lange Folge von Forwards
GOTO
in verschachtelteif
s verwandeln . Die eigentliche Antwort ist jedoch das richtige Refactoring, ohne archaische Sprachkonstrukte zu imitieren.Wenn Sie verzweifelt versuchen würden, einen Algorithmus mit
GOTO
s darin zu transliterieren , könnten Sie dies wahrscheinlich mit dieser Redewendung tun. Es ist sicherlich nicht standardisiert und ein guter Indikator dafür, dass Sie sich nicht genau an die erwarteten Redewendungen der Sprache halten.Mir ist keine C-ähnliche Sprache bekannt, in der do / while eigentlich eine idiomatische Lösung für irgendetwas ist.
Sie könnten wahrscheinlich das ganze Durcheinander in etwas Vernünftigeres umgestalten, um es idiomatischer und viel lesbarer zu machen.
quelle
do..while(false)
ist nicht dafür gedacht, "undefiniert" mehrmals zu laufen, sondern dafür, einmal zu laufen .continue
am Ende eine bedingte Anweisung haben, wie ich gezeigt habe. Damitundefined
meine ich einfach, dass Sie nicht wissen, ob es mehr als einmal ausgeführt wird, es sei denn, Sie können vorhersagen, ob die Bedingungen bei einer bestimmten Iteration erfüllt werden. Ohnecontinue
s drin,do..while(false)
läuft einmal, aber auch ohnebreak
s drin,while(true)
läuft immer, so dass das „Standardverhalten“ nicht wirklich relevant ist , zu verstehen , was kann mit den Schleifen erfolgen.continue
.continue
wiederholt NICHT die Schleife. "Diecontinue
Anweisung darf nur in einer Iterationsanweisung vorkommen und bewirkt, dass die Steuerung an den Schleifenfortsetzungsabschnitt der kleinsten einschließenden Iterationsanweisung übergeben wird, dh an das Ende der Schleife."Einige Codierer bevorzugen nur einen einzigen Exit / Return von ihren Funktionen. Die Verwendung eines Dummys do {....} while (false); ermöglicht es Ihnen, aus der Dummy-Schleife auszubrechen, wenn Sie fertig sind und immer noch eine einzige Rückkehr haben.
Ich bin ein Java-Codierer, also wäre mein Beispiel so etwas wie
quelle
In solchen Fällen benutze ich
quelle
Das ist amüsant. Es gibt wahrscheinlich Unterbrechungen innerhalb der Schleife, wie andere gesagt haben. Ich hätte es so gemacht:
quelle
do..while(false)
Ausgänge immer,while(true)
ist eher riskant.while(true)
ist die richtige Sprache in den meisten Sprachen. Sie finden es häufig in GUI-Anwendungen als Hauptschleife des Programms. Da Sie im Grunde davon ausgehen, dass das Programm nicht sterben sollte, bis es dazu aufgefordert wird,do..while(false)
würde a alle Arten von erfundener Logik verursachen. Dieser Ansatz mag von einem perfektionistischen POV risikoreicher sein, ist jedoch semantisch einfacher und daher für menschliche Programmierer weniger fehleranfällig (sorry, Skynet).do{...}while(false)
ist genau das gleiche wiewhile(true){ .. break;}
continue
, sie sind nicht gleich.