A ''trivial do/while loop'' is a useful device in CeeLanguage consisting of a do/while loop with a loop condition which always fails; i.e: do { /* Execute some code */ } while (0); It's also useful (but to a lesser extent) in CeePlusPlus and JavaLanguage, though the presence of other language features such as destructors (C++), finally (Java), exceptions (both), and inline functions (C++) eliminates the need in some cases. This is useful in two instances. * When you want a scope to break out of, in a sequence of initialization steps that each might fail, to make "cleaning up" a bit easier. This eliminates a common use of GoTo (or the infamous ArrowAntiPattern). Note that in C; you still must take care not to return from inside a TrivialDoWhileLoop, or the best laid plans of mice and men are for nought. * To make a multi-statement CeePreprocessor macro embeddable in a context where a single statement is expected, and have the compiler treat it as a single statement (including requiring a semicolon). Simply putting a group of statements in curly braces doesn't work, because a trailing semicolon will cause havoc with if/else. I.e. #define FOO(x) { do_this(x); do_that(); } doesn't work in the following context if (x>y) FOO(x); else FOO(y); The above won't compile. By replacing the macro definition with the following (note the absence of a trailing semicolon) #define FOO(x) do {do_this(x); do_that(); } while (0) the above if/else clause works properly. This technique is sometimes known as ''swallowing the semicolon''. Advocates of HighLevelLanguages (higher than C, which seems to be any modern language in existence, except for assembly) will of course object that such bletcherous hackery is entirely unnecessary in their favorite language. And they'd be right; however lots of us still write code in C; this trick is useful to know. -- ScottJohnson ''This is also a good demonstration of one (of many) reason that C gave 'macros' a bad name'' * Well, sure, but it's curiously difficult to pin down the problem in this case. * It has to do with semicolons, and of course there are holy wars over whether languages should have them, but when you come right down to it, they're not that big of a deal; they're not one of the major reasons why C is flawed, even if one thinks they're a minor reason. * Is this due to the notoriously bad design of the macro preprocessor? Well, no, not in a glaringly obvious sense, anyway. * It comes down to being a problem with the interaction between semicolons in the main language and the overall characteristics of the macro preprocessor add-on. A more powerful macro facility might allow one to avoid this crud, but the lack of power doesn't directly cause the crud. * Or am I missing something? What would be the smallest change to the language or preprocessor that would make this kludge unnecessary? ''Disallow the use of ; as a null statement; require {} instead. --AdamBerger'' ---- This problem isn't only in C The same semi-colon problem is in Bourne shell and Bash (yes its not a compiled language) also do not allow just a lonely semicolon in if statements. if program; then ; else echo some error The solution here is to use ':;' instead of just ';' The ':' is a 'no-op' shell command, always true. --Anthony Thyssen ---- I never considered anything like that in my years programming C. A forward goto is a lot simpler, as long as you don't follow GotoConsideredHarmful religiously. The second concern didn't apply, since I rarely used macros and always put braces around if, else, for, and while clauses. ''You never wrote a header file that someone else would ever include??? Because the above point is critically important for actually published macros, else you'll break someone else's code.'' [Discussion of C preprocessor moved to CeePreprocessorStatements] ---- I have used a similar-but-different construct in building initialization code sequences, using the switch(){} statement, thus (crudely): switch (1) { default: . . (pass/fail operations) . . } although, some compilers insist on at least one case, so for these: switch (1) { case 0: default: . . (pass/fail operations) . . } As mentioned above, in the first example, I don't return from such a construct, as this violates single-entry/single-exit structure. -- GarryHamilton ''Surely not for the same purpose, though, since this runs afoul of the semicolon problem... so what are you saying you use it for?'' Quite right, I don't use this for macros. My first use was in writing an initialization sequence for a dial-in driver for a terminal emulator running on a PC to establish secure access to a SeriesOne (IBM box). The problem was that NestedIfs became so unwieldy and ugly that I sought to accomplish an "everything succeeds or fall to the bottom with fail code" structure. I tried both the TrivialDoWhileLoop and the TrivialSwitch, and stayed with the switch. The sequence involved something like this: if I have a comm port and it's really there and it's connected to a modem of a type I recognize and it responds to the setup sequences as I expect and it is connected to a phone line and detects a dial tone and will dial out to the remote modem and the remote modem answers and I get connected to the remote SeriesOne and I receive the challenge and I'm able to send the response and I get the go-ahead from the Series 1 driver, then succeed and return to caller with open channel. If at any point any of these steps fails, then fail and return error code to caller. The switch structure allowed the code to be arranged vertically rather than successively indented. If any return code came back non-zero, a simple "break" dropped past the rest of the code to the bottom of the switch. This use is in line with the first bullet point at the top of the page, above the #define. ''That's interesting. Long ago the do-while(0) worked for me for guarded conditions so I never really reconsidered. I'll have to think about that.'' ---- A TrivialDoWhileLoop is IMHO a CodeSmell asking for ExtractMethod (replacing the breaks with returns). ''If only it were so easy to to follow such simple sounding advice, however you missed the explanation at the top of the page, that this is essentially required for certain types of macros. There is no escape from it, in that context.'' I've never needed it for my own macros. Maybe it's because of my coding conventions. Come to think of it, I don't think I've written any C macros that got used by other people. [ I fail to see how you can write macros '''safely''' without following the advice at the top of the page, coding conventions or not, other people or not. That's the point of the macro-related part of this page. Oh, or do you mean you don't put statements in macros? That'll do it. ] ''As for the other use discussed above, the one where "switch" was also offered as an alternate approach (but I assume you would still disapprove), sometimes you could do ExtractMethod, sometimes you can't. Sometimes one is doing guards, a long series of them, and if any fail, you don't want to do the final block of code. You could use a 20 line boolean expression, but that actually is much uglier, which is why do-while(0) and switch() even arise. Why couldn't you do ExtractMethod there? What if each clause of the series of guards used a different local variable? Then you'd need to pass all twenty local variables to the new method.'' I usually find that guard clauses use member variables, so I haven't had the problem. Then again, the original context was CeeLanguage so I see your point. ''Sometimes the purported cure is worse than the disease.'' Point well taken, generally speaking at least. ---- (moved from AlwaysUseBracesOnIfThen -- EditHint: squeeze out redundancy) '''use the TrivialDoWhileLoop in your macros to guard against people who fail to AlwaysUseBracesOnIfThen when they use your macros''' ''Another probable error that is likely to pop up if you don't use braces, is if the one statement after the if is a macro. I once turned a macro containing a simple function call into one using two statements, and my code broke half a mile further down the road. Had braces been used by other programmer on the if statement, or by me on the #define statement, then I wouldn't have spent several hours trying to trace down why my program was inexplicably exiting.... So this entry should actually be named AlwaysUseBraces. -- AndreSlabber'' The trick here, if I recall, is to usually enclose macro definitions in (). If you have multiple statements, separate them with commas, ie: #define macro() (foo(), bar()) If you also have control structures if your macro, then wrap the whole in a do...while statement, like this: #define macro(x, y) do { if (something_is_true) { x; } else { y; } } while (0) ''Actually, it also works if you just use curly braces and semicolons like this: #define macro {statement1; statement2 } -- AndreSlabber'' : ''Actually not, because the above (macro statements enclosed in curlies) has the problem of becoming two statements where the macro name is used followed by a semicolon. That's what the while (0) method is solving: keeping it one statement. Otherwise, with the curlies, we get:'' if (a) macro(); // expands to: {statement1; statement2;}; else something(); : ''Sure, it doesn't compile - so at least it isn't a sneaky error - but in any case the while (0) approach lets it work properly. -- BillKelly'' ''Still, the onus is on the writer of the macro to make it safe by using braces or parens, etc. The idea of braces on the '''if-then''' is different, since the modifying is done the the straight code, just inobservant of the blocking.'' -- Pete Hardie Of course, I'm not saying that I shouldn't have correctly written the macro; I just pointed out that ifs without braces create a nasty little error if you don't think of that. Actually, I think coding straight into the if statement and then doing it wrong is worse, because one can clearly see that there are no braces, and that they should be inserted. -- AndreSlabber ---- ---- ''Merged from orphan Disguised''''''Goto''' A programmer I work with often uses the following construct: do { ... if ( something ) break; ... } while (0); I could not understand why he insisted on writing his code that way... until a friend pointed out to me that this was a GOTO in disguise. The code is similar (though not identical to): { /* provide a nested scope */ ... if (something) goto done; ... done: ; /* I think the semicolon following the label is necessary; it * certainly is in a switch statement */ } ''A similar (and real), but more mysterious version:'' * Not similar at all; the do/while loop executes the body exactly once (leaving early when something occurs); the for loop below executes the loop body infinite times, until something occurs. for(;;){ ... if(something)break; } ''...which strikes as a do-while non-believer.'' Well, I'd say the latter is less mysterious. An infinite loop with a break is easy to grasp. The '''while(0)''' stumped me when I first saw it. Why on earth write a loop that will execute exactly one time?? (The answer: to conceal a GotoStatement.) ''Why should anybody use it, instead of:'' ... if (!something) { ... } ---- There's another reason for do ... while(0) construct: preprocessor macros. It's not something I've used, but on page 174 of CodeReading, the author discusses a use of do .. while(0) to create a block in a macro. He gives an example from the NetBSD vm source. ---- The do ... while(0); construct is used in macros like this: #define M do { stmt; stmt; } while(0) if (x) M; else ... Other ways of having multiple statements in a macro do not allow you to freely add or leave off a ; after invoking the macro. The do while(0) packages up the multiple statements syntactically into a single statement, which can be used in any context. Had the macro been: #define M stmt; stmt; then the following does not work: if (x) M // fails, second stmt; not controlled by if Or had it been: #define M {stmt; stmt; } then the following does not work: if (x) M; // ; not permitted after } before else else stmt; The do { } while(0) works in all the cases. ''The above M macro is a bad coding style in my books, regardless of while(0). In C, macros should be restricted to defining constants or trivial one-liners like max. If you need to tack multiple statements together, put them in a function. In C++, there is little excuse to use macros at all.'' -------------- Jumping out of a block is not '''always''' bad. It should be used judiciously, but sometimes it simplifies the code. ----- Another use for the TrivialDoWhileLoop, not mentioned above, is to stop a function being unexpectedly executed multiple time in a macro pretending to be or substituting a function, for example: #define pretend_function(x) do { int tmpx = (x); if( 0 < tmpx && tmpx < 15 ) { do_something(); } } while(0) So, if some coder does: pretend_function( other_function() ); ...then other_function is only executed once. Obviously, if we were to have done: #define incorrect_function(x) do { if( 0 < (x) && (x) < 15 ) { do_something(); } } while(0) ...then the code for other_function() is executed twice, which may have unexpected results or, at best, waste cycles in the case of a pure function. -- C 2005-12-11 ---- CeeIdioms