Are do-while-false loops common?

2019-01-11 16:40发布

A while back I switched the way I handled c style errors.

I found a lot of my code looked like this:

int errorCode = 0;

errorCode = doSomething();
if (errorCode == 0)
{
   errorCode = doSomethingElse();
}

...

if (errorCode == 0)
{
   errorCode = doSomethingElseNew();
}

But recently I've been writing it like this:

int errorCode = 0;

do
{       
   if (doSomething() != 0) break;
   if (doSomethingElse() != 0) break;
   ...
   if (doSomethingElseNew() != 0) break;
 } while(false);

I've seen a lot of code where nothing gets executed after there's an error, but it has always been written in the first style. Is there anyone else who uses this style, and if you don't, why?

Edit: just to clarify, usually this construct uses errno otherwise I will assign the value to an int before breaking. Also there's usually more code than just a single function call within the if (error == 0 ) clauses. Lots of good points to think on, though.

20条回答
手持菜刀,她持情操
2楼-- · 2019-01-11 17:18

Your method isn't really bad and it's not unreadable like people here are claiming, but it is unconventional and will annoy some (as you noticed here).

The first one can get REALLY annoying after your code gets to a certain size because it has a lot of boilerplate.

The pattern I tended to use when I couldn't use exceptions was more like:

fn() {
    while(true) {
        if(doIt())
            handleError();//error detected...
    }
}

bool doIt() {
    if(!doThing1Succeeds())
        return true;
    if(!doThing2Succeeds())
        return true;
    return false;
}

Your second function should be inlined into the first if you put the correct magic incantations in the signature, and each function should be more readable.

This is functionally identical to the while/bail loop without the unconventional syntax (and also a bit easier to understand because you separate out the concerns of looping/error handling from the concerns of "what does your program do in a given loop".

查看更多
Ridiculous、
3楼-- · 2019-01-11 17:18

I've used the technique in a few places (so you aren't the only one who does it). However, I don't do it as a general rule, and I have mixed feelings about it where I have used it. Used with careful documentation (comments) in a few places, I'm OK with it. Used everywhere - no, generally not a good idea.

Relevant exhibits: files sqlstmt.ec, upload.ec, reload.ec from SQLCMD source code (not, not Microsoft's impostor; mine). The '.ec' extension means that the file contains ESQL/C - Embedded SQL in C which is pre-processed to plain C; you don't need to know ESQL/C to see the loop structures. The loops are all labelled with:

    /* This is a one-cycle loop that simplifies error handling */
查看更多
Explosion°爆炸
4楼-- · 2019-01-11 17:18

Honestly the more effective C/C++ programmers I've known would just use a gotos in such conditions. The general approach is to have a single exit label with all cleanup after it. Have only one return path from the function. When the cleanup logic starts to get complicated/have conditionals, then break the function into subfunctions. This is pretty typical for systems coding in C/C++ imo, where the APIs you call return error codes rather than throw exceptions.

In general, gotos are bad. Since the usage I've described is so common, done consistently I think its fine.

查看更多
放荡不羁爱自由
5楼-- · 2019-01-11 17:19

I think the first one gives you more control over what to do with a particular error. The second way only tells you that an error occurred, not where or what it was.

Of course, exceptions are superior to both...

查看更多
做个烂人
6楼-- · 2019-01-11 17:20

Make it short, compact, and easy to quickly read?

How about:

if ((errorcode = doSomething()) == 0
&&  (errorcode = doSomethingElse()) == 0
&&  (errorcode = doSomethingElseNew()) == 0)
    maybe_something_here;
return errorcode; // or whatever is next
查看更多
孤傲高冷的网名
7楼-- · 2019-01-11 17:20

Why not replace the do/while and break with a function and returns instead?

You have reinvented goto.

查看更多
登录 后发表回答