E
Ersek, Laszlo
The single best example, common cleanup code at the end of a function,
was already given in this thread. If during all your years of
programming, you just had Dijkstra's famous letter in your mind, it may
of course never have occured to you that a goto in such kind of code
would /improve/ the structure.
There's probably not much merit in adding my own preferences to this
thread, but I tend to use the "huge tree of nested if's" Tom St Denis
seems to hate so much (IIRC -- sorry if I'm wrong, Tom!) If the tree grows
too deep, I break it up into functions. I use goto only under exceptional
conditions, where I perceive it to provide a big jump in expressive power.
Example:
----v----
From: "Ersek, Laszlo" <[email protected]>
Newsgroups: comp.unix.programmer
Subject: Re: verifying file ownership with dlopen()
Date: Wed, 5 May 2010 19:01:46 +0200
Message-ID: <[email protected]>
David Schwartz wrote in message
<f37d8057-9e6b-4e9a-a6fd-4371dadd683e@k25g2000prh.googlegroups.com>:
He needs to check every path element that leads to the library, because
either one could be a symlink.
And the check must be aware of the local system's rules for permissions.
For example, just checking the file mode may not be enough if there are
ACLs.
Once the full pathname has been tokenized, the way to do that might be
something like this. (Note - I didn't even try to compile this. It's here
only to invite criticism and/or better ideas.)
int
safeopen(const char * const * elem, size_t nelem)
{
if (0u < nelem) {
int fd;
size_t cur;
fd = open("/", O_SEARCH | O_DIRECTORY | O_NOFOLLOW);
cur = 0u;
loop:
if (-1 != fd) {
struct stat s;
if (0 == fstat(fd, &s)) {
if (cur == nelem) {
if (S_ISREG(s.st_mode) && /* other checks on the executable */) {
return fd;
}
}
else {
if (/* checks on the directory */) {
int tmp;
tmp = fd;
fd = openat(fd, elem[cur], O_NOFOLLOW
| (cur < nelem - 1u ? O_SEARCH | O_DIRECTORY : O_EXEC));
if (0 == close(tmp)) {
++cur;
goto loop;
}
}
}
}
if (-1 != fd) {
(void)close(fd);
}
}
}
return -1;
}
The returned int (if not -1) could be used with fexcve(). Unfortunately
(or not), there is no "dlfdopen()".
The code could hang indefinitely if the last component identified a FIFO.
I'd OR O_NONBLOCK with O_EXEC, if not for O_NONBLOCK being unspecified for
regular files. (I can't see anything in the openat() spec that would
require O_EXEC to fail on a FIFO (and immediately).)
[...]
----^----
Furthermore, nested if's (just like judiciously placed labels) are very
suitable for "cascading release of resources". IIRC, you said something to
the effect of "code should be condensed on the left". I sort of disagree.
Staying with the case where the if-tree still fits reasonably in a
function, I like an indentation that reflects the dependency depth of the
dependent code. (I use a "two spaces" indentation style, obviously.) With
goto's, the dependency depth is the same, but it doesn't show.
A random link:
http://en.wikipedia.org/wiki/Cyclomatic_complexity
goto's probably don't change the control flow graph, just tend to distance
the source's appearance from the CFG.
Nested if's also allow block folding in many editors and "find matching
brace".
lacos