4 ms·
Without goto, you get to maintain several copies of your cleanup code, all different: int insane() { FILE *a = open("a", "r"); if (!a) {
by koenigdavidmj 10y ago
Without goto, you get to maintain several copies of your cleanup code, all different:
int
insane()
{
FILE *a = open("a", "r");
if (!a) {
return -1;
}
FILE *b = open("b", "r");
if (!b) {
fclose(a);
return -1;
}
FILE *c = open("c", "r");
if (!c) {
fclose(a);
fclose(b);
return -1;
}
int rv = (do something with a, b, and c);
fclose(a);
fclose(b);
fclose(c);
return rv;
}
Now here's an example where you only need to maintain one copy of your cleanup code:
int
reasonable()
{
FILE *a = NULL;
FILE *b = NULL;
FILE *c = NULL;
int rv = -1;
a = open("a", "r");
if (!a) { goto out; }
b = open("b", "r");
if (!b) { goto out; }
c = open("c", "r");
if (!c) { goto out; }
rv = (do something with a, b, and c);
out:
if (a) { fclose(a); }
if (b) { fclose(b); }
if (c) { fclose(c); }
return rv;
}
Avoiding goto gets impossible the second you start doing socket twiddling, or message generation. Yes, languages with context managers (Python's with blocks), RAII (C++ or Rust), or defer (Go) make this easier, but some of us are stuck writing C sometimes.
- tzs 10y agoOf course in this case you can avoid both the repetition and the goto at the cost of more nesting: rv = -1; a = open(...); if (a) { b = open(...); if (b) { c = open(...); if (c) { rv = something(a,b,c); close(c); } close(b); } close(a); } return rv; I wonder if there is some sort of program organization analog of Heisenberg's uncertainty principle, where the product of some measure of repetition, some measure of non-structured jumping, and some measure of nesting must be greater than a certain value?