R
Robert Latest
Hello folks,
I'm finding myself in a situation where I write plenty of code where
"stacks" of function calls appear quite frequently, as shown below. Of
course it would be tedious to check the return value of each and every
function call, and I never really warmed to setjmp() and longjmp().
So I modified my error-prone functions to accept an additional
parameter. Before doing anything else, each function performs this
little bit of code:
void foo (int *err)
{
if (err && *err) {
++*err;
} else {
/* do stuff */
/* set *err = 1 when something fails */
}
}
So if an error has already occured elsewhere, the function increments
the value err points to and immediately returns. If an error occurs
inside the function, *err is set to 1 and the function exits. This not
only implements a convenient "fall-through" mechanism, but it also
permits localization of the function call that failed, as shown in the
example code below. I admit the errline idea is definetely taking the
concept too far because it breaks if anything but an err-aware function
call is inserted in between, but you get the drift.
Sample code:
--------------------------
int foo(blah)
{
int err = 0;
int errline;
struct command *cmd;
cmd = cmd_new(&err);
cmd_append16(cmd, CMD_START, &err); /* in my code, I have */
cmd_append32(cmd, p->feedback, &err); /* chunks like this that */
cmd_append32(cmd, p->offset_x, &err); /* span a dozen lines or */
cmd_append8(cmd, p->port, &err); /* more */
cmd_write(link, cmd, &err);
errline = __LINE__-err;
cmd_free(cmd);
if (err) {
fprintf(stderr, "Function call on line %d failed\n", errline);
}
return err ? -1 : 0;
}
-------------------------
What's the point of this posting? If you think this is a cool idea, feel
free to use it in your code. If you think it stinks, tell me why.
Thanks,
robert
I'm finding myself in a situation where I write plenty of code where
"stacks" of function calls appear quite frequently, as shown below. Of
course it would be tedious to check the return value of each and every
function call, and I never really warmed to setjmp() and longjmp().
So I modified my error-prone functions to accept an additional
parameter. Before doing anything else, each function performs this
little bit of code:
void foo (int *err)
{
if (err && *err) {
++*err;
} else {
/* do stuff */
/* set *err = 1 when something fails */
}
}
So if an error has already occured elsewhere, the function increments
the value err points to and immediately returns. If an error occurs
inside the function, *err is set to 1 and the function exits. This not
only implements a convenient "fall-through" mechanism, but it also
permits localization of the function call that failed, as shown in the
example code below. I admit the errline idea is definetely taking the
concept too far because it breaks if anything but an err-aware function
call is inserted in between, but you get the drift.
Sample code:
--------------------------
int foo(blah)
{
int err = 0;
int errline;
struct command *cmd;
cmd = cmd_new(&err);
cmd_append16(cmd, CMD_START, &err); /* in my code, I have */
cmd_append32(cmd, p->feedback, &err); /* chunks like this that */
cmd_append32(cmd, p->offset_x, &err); /* span a dozen lines or */
cmd_append8(cmd, p->port, &err); /* more */
cmd_write(link, cmd, &err);
errline = __LINE__-err;
cmd_free(cmd);
if (err) {
fprintf(stderr, "Function call on line %d failed\n", errline);
}
return err ? -1 : 0;
}
-------------------------
What's the point of this posting? If you think this is a cool idea, feel
free to use it in your code. If you think it stinks, tell me why.
Thanks,
robert