3 ms·
Duff's device is sort-of an example of this, as cases in C are equivalent to goto labels. It's an interesting point, though. I don't think I've ever seen anybo
by tom_ 7y ago
Duff's device is sort-of an example of this, as cases in C are equivalent to goto labels.
It's an interesting point, though. I don't think I've ever seen anybody actually use gotos for this, and I don't remember ever doing it myself. (I will happily put a goto label anywhere that will compile - I'm not against goto in principle.)
I'd assume it's because 99% of the time there's always some other non-goto option that could be used, and C programmers are accustomed to thinking about their programs in terms of these constructs, rather than necessarily goto. goto is always there when all else fails - but when it comes to loops, all else fails rather rarely.
Some (non exhaustive) examples.
Just thinking about the loop mechanics: jumping into the middle of a C for loop probably isn't super-useful, as you're only skipping the one-time init, which you could skip anyway: just leave it empty and put that code elsewhere. Then maybe turn the loop into a while loop? - that's an option. Anyway, for and while are basically equivalent for the purposes of this discussion.
Jumping into the body of a do...while makes it a while, and jumping into the middle of a while makes it a do...while. So C programmers would just write the right sort of loop in the first place.
goto X; ---> do {
while(cond) { A;
X: } while(cond);
A;
}
goto X; ---> while(cond) {
do { A;
A; }
X:
} while(cond)
And regarding the body: jumping halfway into the body is equivalent to one of those annoying loops where the setup for the condition is rather involved. One option here is an infinite loop with a break in the middle, so C programmers might just write the loop that way in preference to the one with a goto.
goto X; ---> for(;;) {
while(cond) { B;
A; if(!cond) break;
X: A;
B; }
}
The do...while case is equivalent.
goto X; ---> for(;;) {
do { B;
A; if(!cond) break;
X: A;
B; }
} while(cond);
Or another option is to pop B in a function, that checks the condition.
while(B()) {
A;
}
- jcranmer 7y ago> Just thinking about the loop mechanics: jumping into the middle of a C for loop probably isn't super-useful, as you're only skipping the one-time init, which you could skip anyway: just leave it empty and put that code elsewhere. Irreducible loops [loops that have multiple entry points] tend to cause compilers to bail out on optimization; there are some algorithms which just don't work on irreducible loops. In a modern optimizing compiler, introducing irreducible loops will not give you a performance benefit and will probably give you steep performance hits instead. I will point out that literally none of your examples are irreducible loops, since you have unconditional gotos immediately before the loops and thus they have only one entry point, even if it isn't the normal lexical entry point.