• Xamuel (unregistered)

    People have been asking why do{...}while(0) is useful in C. One reason is to force macros to have the same syntax as functions. Consider the line:

    for(i=0;i<5;i++) MYMACRO(i);

    If MYMACRO is a naive multi-line macro, then we've got trouble: only the first line will be associated with the for! (Also, the semicolon is superfluous, though that's not fatal.)

    So instead, you define MYMACRO to be do{...}while(0), which transforms multiple lines into one line, and then the above construction works fine. (Also, the semicolon is no longer superfluous)

  • Tuna (unregistered) in reply to ais523
    ais523:
    I've actually done this with a do{}while(0) loop in C, because it was clearer than the alternatives. (This was generated code, btw; the generated version was meant to be readable, but the original was the bit you actually edited.) It's a nice paradigm for what would otherwise lead to 20 nested if statements.

    If you want to use a goto, use a goto. Replacing it with misused structure is not at all better.

  • (cs) in reply to averageGuy
    averageGuy:
    The Nerve:
    bool bCreateModel = false;
    if (!pModel || asModelParts.GetSize() != asModelPartsToLoad.GetSize())
    {
        bCreateModel = true;        
    }
    

    for (UINT32 i = 0; i < asModelPartsToLoad.GetSize() && !bCreateModel; ++i) { if (asModelPartsToLoad != asModelParts[i]) { bCreateModel = true;
    } }

    Fixed?

    Almost, but not quite.

    Your code would execute the for loop when the first condition was true. This would at least be wasteful and might lead to errors if !pModel meant that asModelPartsToLoad was not initialized.

    Putting an the for loop into an else clause would fix that.

    or just switching the order of the conditionals in the second part of the for loop.

    I am pretty certain this is C++ because of the UINT32, the GetSize() and the use of the comparison operator !=.

    It is incorrect usage of C++ but complies with the language.

    [i]Addendum (2010-08-26 06:26): The correct way to do it is the way I outlined on Page 1 it must have been too clsoe to the bottom of the page so I will try to post the correct implementation again. You can do all of this in one statement.

  • (cs)

    Step 1: Get rid of all the nonsense Hungarian notation and use standard STL collections.

    Step 2: Refactor that into one statement:

    createModel = !model 
      || modelPartsToLoad.size() != modelParts.size() 
      ||    !std::equal( modelPartsToLoad.begin(),  modelPartsToLoad.end(), modelParts.begin() );
    
    

    If you can't refactor into STL collections there are still ways to create proper iterators for it so you can use std::equal. &modelPartsToLoad[0] might work if the collection is guaranteed to be contiguous.

  • (cs) in reply to Xamuel
    Xamuel:
    People have been asking why do{...}while(0) is useful in C. One reason is to force macros to have the same syntax as functions.

    Why make it so complicated. If you want to force it to run at least one iteration, use do/while, if you want to check the condition before doing any iterations, use while or a for loop.

  • kastein (unregistered) in reply to Coder
    Coder:
    1000 Every language that has a label or line-number 1010 that you can GOTO has a COMEFROM problem. It is 1020 not the GOTO that is the problem (although a 1030 computed GOTO is a bit of a problem). GOTO 1050 1040 OK, WHERE DID THIS LINE COME FROM ? 1050 It is the come-from that is the problem.

    Note: this comment has a bug.

    Error 18 on line 1000: Function not defined: Every Error 18 on line 1010: Function not defined: that Error 18 on line 1020: Function not defined: not Error 18 on line 1030: Function not defined: computed Error 18 on line 1040: Function not defined: OK Error 18 on line 1050: Function not defined: It

    Those are the only bugs I could find :(

    had forgotten my BASIC error numbers, googled for a reference and good lord! Someone is working on a 64 bit edition of qbasic that supports Linux and Windows. I felt dirty after discovering this.

    Corey:
    my idea:

    Regex exp = new Regex( @"(i('ve)(\s)+..you('re|r).(pray).*further)|(bert.*g(.){1,5}ron)|(f[ri1][ri1]st)", RegexOptions.IgnoreCase)

    if(exp.IsMatch(CommentText)){ //TODO: Insert code that will find the poster and urinate on them }

    How well do you know javascript / DOM trees, are you familiar with greasemonkey, and how much beer do I owe you?

  • Design Pattern (unregistered) in reply to newfweiler
    newfweiler:
    I remember the proposal to add COMEFROM, COMEFROM DEPENDING ON, (computed COMEFROM) and conditional COMEFROM to COBOL and ForTran.
    The only clean implementation of COMEFROM was in Threaded INTERCAL.
    newfweiler:
    The modern language that has COMEFROM is Java, only it's called "Annotations".
    Nope.

    What it's really called is "Aspect-Oriented Programming".

    newfweiler:
    It's useful for application platforms where you want to call your own method from platform code, without modifying the platform code to add a line to call your method.
    But in that case the developer of the platform code KNOWS that he will jump into other people's code.
  • zarg (unregistered)

    This is a variation of a pattern that allows error handling in a single place if you're using a language like C that doesn't support exceptions. It's probably better to use a goto:

        model_t* pModel = 0;
        part_t* pParts = 0;
    
        pModel = GetModelinstance();
        
        if (!pModel)
        {
            goto error;
        }
    
        pParts = GetParts( pModel);
        if (!pParts) 
        {
            goto error;
        }
        
        // etc...
        
        
        PartsRelease( pParts);
        ModelRelease( pModel);
        return 0;
    
    error:
        if (pParts) 
        {
            PartsRelease( pParts);
        }
        if (pModel) 
        {
            ModelRelease( pModel);
        }
        
        return -1;
    

    However, there are a lot places where using a goto even where it makes sense is irrationally considered very bad practice. In a situation like that, it might make sense to use the break statement as in the example.

    A better way to handle that situation (if the "goto error;" isn't permitted or desired) might be to use a "do {} while (false)" statement instead of a "for (;;) {}".

  • ateu (unregistered)

    DE-WTF:

    if (!pModel)
    {
        bCreateModel = true;
    }
    elseif (asModelParts.GetSize() != asModelPartsToLoad.GetSize())
    {
        bCreateModel = true;
    }
    else for (UINT32 i = 0; i < asModelPartsToLoad.GetSize(); ++i)
    {
        if (asModelPartsToLoad[i] != asModelParts[i])
        {
            bCreateModel = true;
            break;
        }
    }
    
  • MMXII (unregistered) in reply to A Tester

    You don't have to complete the inner loop as it's just looking for the first occurrence of inequality.

  • SurturZ (unregistered)

    It amazes me how stupidly people will code, just to avoid a GOTO.

    http://slashdot.org/journal/145833/In-defense-of-GOTO

    The "Do ONCE" construct is a common anti-pattern.

  • (cs) in reply to SurturZ
    SurturZ:
    It amazes me how stupidly people will code, just to avoid a GOTO.

    http://slashdot.org/journal/145833/In-defense-of-GOTO

    The "Do ONCE" construct is a common anti-pattern.

    The scenario referred to in the article is only applicable for the C language.

    In C++ you have RAII, which effectively involves creating scoped objects whose destructors invoke when they go out of scope. As a result you do all your "clean-up" in those.

    There there is no need for goto or finally in try-catch blocks.

  • Tanuki (unregistered)

    Let us see, gotos are uncivilized and the workarounds just plain ugly. I know! I use goto but wrap it up to some macros to make it more structured. At least it directly spells no goto in the source file, so aren't you happy?

    /*T stands for trap*/
    
    typedef void* TLEAP;
    
    #define TLEAP_INIT(leaptype) (leaptype = NULL)
    
    #define TLEAP_DESTINATION(label_name) _label_##label_name:
    
    #define TLEAP_RESET(leaptype) (leaptype = NULL)
    
    #define TLEAP(ticket,label_name) \
            do{\
                    ticket=&&_CC(_tleap_,__LINE__);\
                    goto _label_##label_name;\
                    _CC(_tleap_,__LINE__):;\
                    ticket = NULL;\
            }while(0)
    
    #define TLEAP_RETURN(ticket) do{if(ticket) goto *ticket;}while(0)
    
    #define _CC(A,B) _CC2(A,B)
    #define _CC2(A,B) A##B
    

    Used in a simple parser program.

  • MR O (unregistered)

    Actually, I have also seen this kind of code, except that the programmer mask it in macros like

    BEGIN_BS BREAK_IF( cond ); BREAK_IF_WITH( cond, var = value ); END_BS

    I first read the BS as you know, BS. And I think it is utter BS.

  • Shinobu (unregistered) in reply to zzo38

    Sure, this particular case might have been structured better, but in general this isn't a bad pattern. In VB, I've seen Do ... Loop While False used a lot, especially where some things need to be done, then a check, then some more actions, another test, and so on. Such code is much clearer than the equivalent with Gotos, and a lot less Alpine than nested Ifs. The language just doesn't have Do ... Once and you can't blame the coder for that. In C++ you might do something like ‘#define once while(false)’ although then ‘once { ... }’ won't do what you expect at all... You might ‘guard’ yourself against this with an extra semicolon, but that actually causes a more insidious problem. All in all, I prefer not to use #defines this way.

    zzo38:
    Actually QBASIC (Microsoft BASIC) also allows RETURN to a different line number or line label, and I have used that feature, for a few different reasons. One was to simulate the effect of the INTERCAL command PLEASE RESUME #2
    You know you're hard core when you're missing your favourite Intercal command.

  • Lo'oris (unregistered) in reply to NASA Engineer

    Uh?

    This is quite common, actually.

    And quite useful, too.

    GOTO will not eat your soul, despite what the Church of the Holy Syntax might say, and tricks such as this one are even more harmless.

    Did you really say you would have preferred three nested ifs? WTF?

  • INTERNETS (unregistered) in reply to NASA Engineer

    It's possible that this is just for historical reasons. It may have originally done something in the for() loop which was removed, leaving the code looking like that.

  • Shinobu (unregistered) in reply to Shinobu

    (replying to myself) ‘#define once while(false);0’ works, since the 0 can't be followed by an { or most statements, so the temptation of writing ‘once { ... }’ won't be there. But is harmless when followed by a ; except when the next statement is an else: ‘if(...) do { ... } once; else ...;’ is invalid. It could be rewritten as ‘do { if(!...) { ...; break; } ... } once;’ but I still think that the preprocessor solution isn't ideal and I won't use it.

  • distineo (unregistered) in reply to Jay
    Jay:
    Seriously, though, this is my problem with people who insist on following a dogmatic rule without bothering to udnerstand why the rule was invented in the first place.

    Yet you fail to elaborate the reasons why the rule was invented. Goto isn't evil because it is spelled g-o-t-o.

    One reason not to use goto is that program flow can jump to anywhere. You have to find the label to know where execution is going to jump to.

    Not with 'do {} while (0);' - this jumps to the end of the block which is easily located.

    When you encounter a label in the source, the gotos leading there may again be anywhere in the code. No problem with 'do {} while (0);' because all the breaks have to be in the braces.

    Jumping into a construct is an issue with a real goto but it isn't possible with 'do {} while (0);'.

    Calling 'do {} while (0);' a goto is misleading, nay, outright wrong, except if you call it a structured goto ;-)

    Personally I prefer 'switch (0) { default:' on one line, and a comment above it. The 'while ()' and 'for (;;)' constructs make people expect a loop that isn't there - and there is even the theoretical risk of an infinite loop if you manage to misplace a 'continue'.

    There are lots of things that "everybody knows" that have no foundation.

  • letatio (unregistered) in reply to Stuck in the Tarpit
    Stuck in the Tarpit:
    Everyone accepts that it's wrong to have a function with multiple return points. Many code-scouring tools identify that as a problem.

    I don't, and I make my own opinion instead of taking a tool's output for canon.

    A return ensures that execution flow cannot reach those points that it should not reach, so there's no need for elaborate if () conditions or else chains.

  • dgghua (unregistered)

    Good article you post! It enlarge my knowlege on the point!Thank You for the post. I love to read interesting post that has knowledge to impart. I hope to read more articles from you and in return I will post also my articles in the forum so that others can benefit from it. Keep up the good work!

  • Tanuki (unregistered) in reply to letatio

    Or, in a slightly pascalish manner, one could define a single variable where to put the return value and use goto to get to the return statement at the end of the function.

    Though that would equally sic the purists after my ass, which is ironic, as I've heard more than once "a nested function with multiple return points as a structured substitute of goto." Supposedly those people have misunderstood the purest meaning of structured programming.

  • got an idea (unregistered)

    well

    i am not sure, why they always use a for look for this construct

    a better way could have been another loop:

    do {

    if 1... break; if 2... break; break; <--- can now be ommited } while (FALSE);

  • random (unregistered) in reply to NASA Engineer
    NASA Engineer:
    No, you guys don't get it. This loop works like the "slingshot" maneuver that probes do to pick up speed before leaving orbit. Using a loop and then breaking out of it actually makes the code run faster!

    ROTFLOLOLOLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOLLOL

  • (cs)

    The main issue here is that it's a borderline case.

    Consider what's really happening.

    if (check1)
        bCreateModel = true;
    else if (check2)
        bCreateModel = true;
    else
        /* Do expensive test to see if bCreateModel should be true.*/

    Sure, that could be done as an if/else with little change.

    But really. Multiple functions? Multiple returns from a function? For this code? Personally, I go through code where people have lazily peppered returns randomly all over their functions and refactor them to have single flow - for me functions are much easier to follow when they enter and exit in one place, not to mention easier to handle in a debugger, something that far too few developers actually use. With a single point of return, there's none of this "Oh ... I didn't see that return buried in the middle of that if/else in the for loop."

    I would not use the construct given for something that simple; in fact I wouldn't use it at all because

    for (;;)
    is very commonly used to mean "forever".

    On the other hand, I use do{}while(0); very often for cases such as the following:

    bool succeeded = false;
    do
        {
        doExpensiveInitialization();
        if (fails)
            break;
    
        doExpensiveInitialization();
        if (fails)
            break;
     
        ...
        succeeded = true;
        }
    while(0); // For control flow only
    return(succeeded);

    All the if/else-happy happy folks would be stuck doing something like the following (which I've seen far too many places in our code):

    bool succeeded = false;
    if (!fails)
        {
        doExpensiveInitialization();
        if (!fails)
            {
            doExpensiveInitialization();
            if (!fails)
                {
                /* ad nauseum */
    
                succeeded = true;
                }
            }
        }
    return(succeeded);

    Note: the real WTF is that the Java folks realized what the C++ folks didn't - a simple named break solves this quite cleanly without introducing the randomness of a GOTO:

    FAILURE:
        {
        doExpensiveInitialization();
        if (fails)
            break FAILURE;
    
        ...
        }

    Now, that is code that has obvious purpose and design without having to hope that intent is clear because the language is not.

  • me (unregistered)

    Ah, c'mon. There are sometimes legit reasons for that sort of construction in C: one-stop resource cleanup. Something like:

       char *a = 0, *b = 0, *c = 0;
       int ok = 0;
       do {
          a = malloc(...);
          ...stuff...
          if (...) break;
          ...more...
          if (...) break;
          b = malloc(...);
          ..blah...
          if (...) break;
          c = malloc(...);
          ok = 1;
        } while (0);
        free(a);
        free(b);
        free(c);
        if (!ok) return;
    

    It's definitely safer/less cumbersome to have all the cleanup code in one place, rather than writing a 'return' where I have each 'break', and trying to make sure you do the right cleanup in each place.

    Sure, you can do the same with a 'goto' but this is, I think, a little cleaner. It should be self-evident that the final clauses get allocated.

    Something like try-finally would be better, but if your language don't got that, you have to make one up.

    (But note do-while(0) rather than for(ever))

  • M2tM (unregistered) in reply to me

    Let me clarify here a few things about this.

    1. This is C++, not C.
    2. There is a simple way to implement this with a single if/else (replacing the loop/break) which more directly expresses intent.
    3. If you want to go a step further it can be made into its own method.
    4. There is no master plan behind this code, you are not witnessing a common idiom in our code base. Much of the 7000 line file I was roaming through contained reams of magic constants and hard coded logic which should have been represented in configuration files.

    This particular example is ridiculous and if you are defending this style of coding I can only say I'm happily not working with you. A few programmers here I shared this with said wtf and suggested I submit it.

  • Ntx (unregistered) in reply to by

    Yes, that's sublime dude!

Leave a comment on “Masquerading as a Loop”

Log In or post as a guest

Replying to comment #:

« Return to Article