Discarded Function Values (To Cast or Not to Cast)

T. William Wells bill at twwells.com
Fri Dec 8 03:58:02 AEST 1989


In article <11680 at smoke.BRL.MIL> gwyn at smoke.BRL.MIL (Doug Gwyn) writes:
: In article <1989Nov23.233403.2841 at twwells.com> bill at twwells.com (T. William Wells) writes:
: >function returns value which is always ignored
: >    fprintf         umask           putenv
: >    setgid          setuid          time
: >    signal          strcpy          unlink
: >    fflush          printf          sprintf
: >    strcat          sleep           fputs
: >(The sum total of lint warnings from a program *under
: >development*. I can tell you why *each* of these is there. And I
: >can tell you, also, which I'm not going to get rid of in the
: >production version.)
:
: Anybody maintaining this code will have to determine why EACH warning
: occurs and whether or not it represents a potential problem.  For
: example, when *printf() and fflush() report errors, is it really safe
: to not detect that?  In most production applications, it would be a
: serious mistake to ignore an output error.

In this case, each output function is either an output to stderr,
debugging output, or later checked with ferror. There are similar
reasons for most of the other functions. The ones where some
reason does not exist will eventually go away.

The primary reason that I ignore the function return value
messages is that I believe that adding the extra casts detracts
from readability. Between that, and the minor irritation of
putting in all the casts, I decided that, in many cases, it is
not worth it to eliminate those messages. It is also worth noting
that, for example, casting the one sleep call (in this bit of
code) to void does not mean that the reader of the code is spared
the necessity of figuring out why the result of the sleep is not
used. For that, a comment is necessary. In which case, the cast
becomes redundant. (And actually, in this case, the comment isn't
even necessary. I'm just using it in a busy loop [argh!] and that
a shortened delay is mostly harmless is obvious.)

The best argument I've heard for always eliminating them is that,
if someone has to add a use of a function in this list, he needs
to be more careful about what he does with return values than he
would otherwise. (I.e., he can't rely on lint catching him if he
forgets to use a return value he should have.)

The other argument, that these messages might indicate a problem
in the code, I find less valuable. This is because I always do
code reviews. When I do a code review, I have to check just as
carefully a cast function as I do one whose return value is
ignored. Accordingly, the cast does not make my job easier. The
person who would benefit is someone who has to take my code and
figure out what I've done. Adding the cast would tell him that
*I* think that the function result should be ignored; I don't
know about you, but when I see such in other's code, I tend to
not take their word for it unless the reasons are obvious, in
which case the cast doesn't help much.

It is a trade-off. I'm on the side of permitting a short list of
these functions. I wouldn't have a conniption if I were required
to eliminate them all, but I don't see a compelling reason to.

: Your code may be perfectly okay, but from years of experience
: maintaining UNIX system code written by other people, I've found
: that I cannot afford to ignore such "lint" warnings.  If, on the
: other hand, I've taken the trouble to completely inspect and de-lint
: a chunk of software, then at any future date when "lint" shows up in
: it I know there is a real problem.  In the long run it saves me time.

Generally this is true. I make only two exceptions to the rule.
The first is for the function return value which is never used,
the second is for things that it is difficult or wrong to make
lint shut up about. (For that latter, consider bugs in lint.)

I'm ambivalent on what to do with things that take #ifdef lint to
make lint shut up. Doing it for malloc is one thing, one can
arrange that all the checking that should be done gets done. But
using #ifdef lint just to eliminate a bit of code that lint won't
otherwise shut up about strikes me as dangerous. On the flip side,
leaving around random lint warnings isn't good either. But the
only solution seems to be to recode, often in ways that causes
other problems.

: P.S. I don't think you should take counterarguments so personally.
: As I said, if your approach works for you, more power to you.  Mine
: certainly works better for me.

If it had been a counterargument, I wouldn't have taken it
personally. I'm sick up to here with ad hominems where arguments
belong. Hence my nasty response to him.

---
Bill                    { uunet | novavax | ankh | sunvice } !twwells!bill
bill at twwells.com



More information about the Comp.lang.c mailing list