while(1) .. break instead of goto

2019-01-18 03:18发布

I found the following code in a C program:

while (1)
{
    do_something();
    if (was_an_error()) break;

     do_something_else();
     if (was_an_error()) break;

     [...]

     break;
}
[cleanup code]

Here while(1) is used as local emulation of "finally". You can also write this using gotos:

do_something()
if (was_an_error()) goto out;

do_something_else()
if (was_an_error()) goto out;

[...]
out:
[cleanup code]

I thought the goto solution is a usual idiom. I have seen several occurrences of this idiom in the kernel sources and it is also mentioned in Diomidis Spinellis' "Code Reading" book.

My question is: What solution is better? Is there any specific reason to use the while(1) solution?

Question 943826 doesn't answer my question.

标签: c goto
13条回答
一夜七次
2楼-- · 2019-01-18 03:35

While using "goto" for error handling situations is fairly common, I'd still prefer the "while" solution (or "do while"). In the "goto" case, there are far fewer things that the compiler can guarantee. If you make a typo in the label name, the compiler can't help you there. If someone uses another goto to another label in that block, there's a good chance the cleanup code won't get called. When you use the more structured flow control constructs you are always guaranteed which code will run once the loop is over.

查看更多
啃猪蹄的小仙女
3楼-- · 2019-01-18 03:43

I like the while(1) approach. I use it myself. Especially, when the loop might get repeated by continue, e.g. when an element is processed inside such loop, and it's done in multiple approaches.

查看更多
劫难
4楼-- · 2019-01-18 03:45

Use it if you can't use goto for whatever reason

  • forbidden in your project's conventions
  • forbidden by your lint tool

I also think that is also one of the cases where macros aren't evil:

#define DO_ONCE for (int _once_dummy = 0; _once_dummy < 1; _once_dummy++)
查看更多
smile是对你的礼貌
5楼-- · 2019-01-18 03:46

"break" understands the semantics of the block scope, while "goto" is oblivious to it. In other words, "while-break" can be translated into functional languages like Lisp with tail-recursion, "goto" cannot.

查看更多
对你真心纯属浪费
6楼-- · 2019-01-18 03:49

The seemingly universal revultion to GOTO is largely due to Edsger Dijkstra's letter "Go To Statement Considered Harmful".

If you are determined not to use goto, something like

do {
    ...
while(0);

is probably safer than while(1) { ... } since it guarantees that you will not inadvertently loop (and if you are inadvertently looping, with while(1) you are probably inadvertently looping infinitely).

The one advantage that (ab)using do/break/while or while/break for this purpose has over goto is that you are guaranteed not to be jumping above the construct -- goto can be used to jump to a label earlier within the same function.

The disadvantage that do/break/while etc. have over goto is that you are limited to one exit point (immediately after the loop). In some cases you might need a staged cleanup: e.g., when you open a file handle, malloc some memory, read from the file... if the read fails, you need to clean up the malloc. If the malloc fails, you don't need to clean it up, but you still need to clean up the file handle. With goto, you can have one label per stage of cleanup and jump to precisely the right point depending on where your error occurred.

In my opinion blindly avoiding GOTO because of the prevalent hatred of it is more damaging than carefully reasoning out a case for its use on a case-by-case basis. A rule of thumb I use is "does the Linux kernel do it? If so, it can't be that bad". Substitute linux kernel with any other good example of modern software engineering.

查看更多
【Aperson】
7楼-- · 2019-01-18 03:52

Never use a condition loop with a permanently true condition. Since the condition is always true, why use a conditional loop?

Permanently true conditions are most directly represented by a goto.

查看更多
登录 后发表回答