[comp.lang.c] Discarded Function Values

ck@voa3.UUCP (Chris Kern) (11/17/89)

I suspect this is not a novel inquiry, but I can't remember any
previous discussion. . . .

My compiler (pcc) is agnostic about discarding the value from a
function call.  Lint, of course, protests.

If it's my function, I presumably will declare it to be void if
it doesn't return a value and will use the value if it does return
one.  But what about a standard library function whose value I
(perhaps recklessly) wish to ignore?  Should I cast the function
call to void, or am I just indulging in the trivial luxury of
silencing lint?

-- 
Chris Kern			     Voice of America, Washington, D.C.
...uunet!voa3!ck					+1 202-485-7020

sullivan@aqdata.uucp (Michael T. Sullivan) (11/17/89)

From article <316@voa3.UUCP>, by ck@voa3.UUCP (Chris Kern):
> ...  Should I cast the function
> call to void, or am I just indulging in the trivial luxury of
> silencing lint?

Although you are merely silencing lint, you are also doing yourself
a service.  If you start letting warnings like "return value ignored"
pop up then you will someday miss an real warning/error message that
is buried amongst the "fake" warning/error messages.  Silence as many
lint warnings as you can (will somebody PLEASE do something about the
malloc bugaboo) and the real ones will stand out easily.
-- 
Michael Sullivan          uunet!jarthur.uucp!aqdata!sullivan
aQdata, Inc.
San Dimas, CA

gwyn@smoke.BRL.MIL (Doug Gwyn) (11/17/89)

In article <316@voa3.UUCP> ck@voa3.UUCP (Chris Kern) writes:
>But what about a standard library function whose value I
>(perhaps recklessly) wish to ignore?  Should I cast the function
>call to void, or am I just indulging in the trivial luxury of
>silencing lint?

C does not require the (void) cast of the unused return value.
As a matter of policy, you shouldn't do things JUST to "shut lint up".
Lint is warning you that functions return success status etc. by
design and that it may be unwise to fail to check the returned status.
Therefore, I would say that for each such warning you should THINK
whether or not the returned value is important for the context in
which the function is invoked, and if so do something about it, or
if not then explicitly discard the value with a (void) cast.  If you
follow that policy, then the reader of your code will KNOW that (void)
means that you've thought about it and decided the return value was
not needed.  Without the explicit (void) he would have no way to tell
if there had been an oversight.

duane@anasaz.UUCP (Duane Morse) (11/18/89)

In article <316@voa3.UUCP>, ck@voa3.UUCP (Chris Kern) writes:
[ My compiler (pcc) is agnostic about discarding the value from a
[ function call.  Lint, of course, protests.
[ If it's my function, I presumably will declare it to be void if
[ it doesn't return a value and will use the value if it does return
[ one.  But what about a standard library function whose value I
[ (perhaps recklessly) wish to ignore?  Should I cast the function
[ call to void, or am I just indulging in the trivial luxury of
[ silencing lint?

We've found that lint catches programmer bugs often enough to make it
worthwhile to do the casts of standard library functions, so much so
that we require all programs to 'pass' lint before they can be released.
Lint can point out bugs that would take a programmer hours to find,
so we believe there's no excuse _not_ to use lint.
-- 

Duane Morse	e-mail: duane@anasaz (or ... asuvax!anasaz!duane)
(602) 861-7609

bill@twwells.com (T. William Wells) (11/18/89)

In article <1989Nov17.154621.2698@aqdata.uucp> sullivan@aqdata.uucp (Michael T. Sullivan) writes:
: From article <316@voa3.UUCP>, by ck@voa3.UUCP (Chris Kern):
: > ...  Should I cast the function
: > call to void, or am I just indulging in the trivial luxury of
: > silencing lint?
:
: Although you are merely silencing lint, you are also doing yourself
: a service.  If you start letting warnings like "return value ignored"
: pop up then you will someday miss an real warning/error message that
: is buried amongst the "fake" warning/error messages.  Silence as many
: lint warnings as you can (will somebody PLEASE do something about the
: malloc bugaboo) and the real ones will stand out easily.

I don't worry about lint warnings about functions whose return
value is never used. It is generally a very short list, things
like strcpy and the like, where the return value is never of
interest to me. I use a cast to void when I ignore the return
value of a function whose return value is used elsewhere.

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

gwyn@smoke.BRL.MIL (Doug Gwyn) (11/19/89)

In article <1989Nov18.062322.12728@twwells.com> bill@twwells.com (T. William Wells) writes:
>I don't worry about lint warnings about functions whose return
>value is never used. It is generally a very short list, ...

If it isn't a problem for you, more power to you.
I find that I am less likely to overlook genuine problems
reported by "lint" if NO lint output is expected than if
SOME lint output is expected.  This is difficult to enforce
when malloc() is involved, although there are ways.

bill@twwells.com (T. William Wells) (11/20/89)

In article <11644@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
: In article <1989Nov18.062322.12728@twwells.com> bill@twwells.com (T. William Wells) writes:
: >I don't worry about lint warnings about functions whose return
: >value is never used. It is generally a very short list, ...
:
: If it isn't a problem for you, more power to you.

Not so long as I keep the list *short*.

: I find that I am less likely to overlook genuine problems
: reported by "lint" if NO lint output is expected than if
: SOME lint output is expected.  This is difficult to enforce
: when malloc() is involved, although there are ways.

I've found that completely shutting up lint is not worth my time.
Not that it is impossible, but I have better things to do.

For example, read() and write(), on different machines, take
either an unsigned int or an int as their third arguments; while
one *could* set things up so that lint won't complain about this,
why bother?

Another gotcha is those irritating truncated long messages; at
least one lint I've worked with won't stop them even if you use a
cast. (And what is so irritating is that one *can't* ignore them.)

Another irritation is the sizeof problem. Things that want a size
should take an unsigned something (or a size_t). But sizeof often
generates an int, which some lints complains about.

Anyway, my approach to this is to shut lint up on anything where
I might be confused by its output, and ignore the rest. (In one
case, I got sufficiently irritated that I wrote a script to
remove the noise. This is risky, unfortunately.)

One thing that helps is that I do most of my work development at
home on my sysV/386 and immediately port it to the Sun at work.
(Typically, I develop it here at home and then run it there:
4MIPS bests ~2MIPS, especially when it takes two hours even at 4!)
Porting is usually a copy, but I sometime catch errors that way.
The real advantage is that, when coding, I am pretty much required
to keep in mind that there are at *least* three other kinds of
machines that my code *will* be run on.

That is a real incentive to avoid those practices that lint would
otherwise complain about.

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

jeffrey@algor2.algorists.com (Jeffrey Kegler) (11/20/89)

In article <11644@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
>In article <1989Nov18.062322.12728@twwells.com> bill@twwells.com (T. William Wells) writes:
>>I don't worry about lint warnings about functions whose return
>>value is never used. It is generally a very short list, ...
>
>If it isn't a problem for you, more power to you.
>I find that I am less likely to overlook genuine problems
>reported by "lint" if NO lint output is expected than if
>SOME lint output is expected.  This is difficult to enforce
>when malloc() is involved, although there are ways.

I always make lint produce silent output, even when writing device
drivers.  Even if you can remember which lint messages are harmless,
someone inheriting your code has to examine them all, or ignore them
all.  And a few months later, if lint produces 7 messages instead of
6, I do not feel all that sure that 7th would catch my attention.  One
instead of zero, I will notice.
-- 

Jeffrey Kegler, Independent UNIX Consultant, Algorists, Inc.
jeffrey@algor2.ALGORISTS.COM or uunet!algor2!jeffrey
1762 Wainwright DR, Reston VA 22090

diamond@csl.sony.co.jp (Norman Diamond) (11/21/89)

In article <1989Nov19.171815.17445@twwells.com> bill@twwells.com (T. William Wells) writes:

>I've found that completely shutting up lint is not worth my time.

Agreed, but for the sake of curiosity...

>Not that it is impossible, but I have better things to do.

What DO you do about calls to malloc?

-- 
Norman Diamond, Sony Corp. (diamond%ws.sony.junet@uunet.uu.net seems to work)
  Should the preceding opinions be caught or     |  James Bond asked his
  killed, the sender will disavow all knowledge  |  ATT rep for a source
  of their activities or whereabouts.            |  licence to "kill".

kremer@cs.odu.edu (Lloyd Kremer) (11/22/89)

The only way I've found to shut lint up about malloc calls is:

	lint | grep -v 'possible pointer alignment problem'

Does anyone have a better way?  Please share it with us so we can stop
talking about this particular bugaboo.

					Lloyd Kremer
					kremer@cs.odu.edu
					Have terminal...will hack!

peter@ficc.uu.net (Peter da Silva) (11/22/89)

Wouldn't this be simpler?

>     #ifdef lint
!     #   define  malloc(x)       (x, 0)
>     #else
>         extern char             *malloc();
>     #endif
-- 
`-_-' Peter da Silva <peter@ficc.uu.net> <peter@sugar.lonestar.org>.
 'U`  --------------  +1 713 274 5180.
"I agree 0bNNNNN would have been nice, however, and I sure wish X3J11 had taken
 time off from rabbinical hairsplitting to add it." -- Tom Neff <tneff@bfmny0>

bill@twwells.com (T. William Wells) (11/22/89)

In article <11161@riks.csl.sony.co.jp> diamond@ws.sony.junet (Norman Diamond) writes:
: What DO you do about calls to malloc?

Something like:

extern void *real_alloc();
#ifdef lint
static void fake_alloc(n) unsigned n; { (void)real_alloc(n); }
#define myalloc(x) (fake_alloc(x), 0)
#else
#define myalloc(x) real_alloc(x)
#endif

When lint is not defined, myalloc just goes to real_alloc, which
does things like checking for out of memory after the call to
malloc.

When lint is defined, myalloc has the call to fake_alloc in order
to type check its argument, and the zero is what the cast that
goes with the myalloc sees. Lint doesn't mind casting the zero,
so there are no complaints.

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

kilroy@mimsy.umd.edu (Nancy's Sweetie) (11/23/89)

In article <11644@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
> I find that I am less likely to overlook genuine problems reported by
> "lint" if NO lint output is expected than if SOME lint output is expected.
> This is difficult to enforce  when malloc() is involved, although there
> are ways.

With which I totally agree:  shut up lint.  Completely.

In article <1989Nov19.171815.17445@twwells.com> bill@twwells.com
(T. William Wells) writes:
>
>I've found that completely shutting up lint is not worth my time.
>Not that it is impossible, but I have better things to do.

and

>Anyway, my approach to this is to shut lint up on anything where
>I might be confused by its output, and ignore the rest.

Which irritates me more than I can express.  (Though I'll try anyway.  8-)

At the NIH Department of Nuclear Medicine, I have to support a program which
does real-time data aquisition.  The original version of this program, I am
told, `produced little output from lint.'

It has since been modified 32 times.  Each person who touched it made a
little change here, a little change there, and never bothered to make sure
they didn't add to the lint output.

When I got this thing, I looked at it for a while, and then ran lint on it.

I got back 851 lines of output, some of which said things like `67 lines
deleted for lack of space.'

Now, you may feel that you have better things to do, and you may feel that
*you* are not confused by some of the messages.  But if you don't care to
put *hard work* into making your programs maintainable for the next guy who
comes along, then why are you even bothering to write programs?

I also have things to do besides spend a half hour ensuring that a program
that works has all the lint-shutter-uppers in it.  But a little hard work
never killed anybody, especially if it can help the next person in line.
Nobody will ever get *any* lines of output running lint on a program I've
written, let alone ~800.


kilroy@cs.umd.edu          Darren F. Provine          ...uunet!mimsy!kilroy
"If everybody gives a little, everybody gets a lot." -- Pete Cottrell

bill@twwells.com (T. William Wells) (11/24/89)

In article <20882@mimsy.umd.edu> kilroy@mimsy.umd.edu (Nancy's Sweetie) writes:
: In article <11644@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
: > I find that I am less likely to overlook genuine problems reported by
: > "lint" if NO lint output is expected than if SOME lint output is expected.
: > This is difficult to enforce  when malloc() is involved, although there
: > are ways.
:
: With which I totally agree:  shut up lint.  Completely.
:
: In article <1989Nov19.171815.17445@twwells.com> bill@twwells.com
: (T. William Wells) writes:
: >
: >I've found that completely shutting up lint is not worth my time.
: >Not that it is impossible, but I have better things to do.
:
: and
:
: >Anyway, my approach to this is to shut lint up on anything where
: >I might be confused by its output, and ignore the rest.
:
: Which irritates me more than I can express.  (Though I'll try anyway.  8-)
:
: [He then goes on to describe a program modified by a bunch of asshole
: programmers.]

If someone wants to take my code and do stupid things with it, I
can't stop him. Even if I had written my code to be lintless, had
they not used lint after each modification, it would be as bad as
if I had left in lint warnings.

: Now, you may feel that you have better things to do, and you may feel that
: *you* are not confused by some of the messages.  But if you don't care to
: put *hard work* into making your programs maintainable for the next guy who
: comes along, then why are you even bothering to write programs?

Because, you asshole, I *do* put hard work into my programs. But
there are are better things for me to do than to deal with this:

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.)

(Why the obscenity? If people throw ad hominems at me, I feel it
perfectly reasonable to return them in kind.)

: I also have things to do besides spend a half hour ensuring that a program
: that works has all the lint-shutter-uppers in it.  But a little hard work
: never killed anybody, especially if it can help the next person in line.
: Nobody will ever get *any* lines of output running lint on a program I've
: written, let alone ~800.

EXCUSE me. If I have a half hour to spend, I have to decide on
where it is best spent. Since I'm already chin deep in things to
do, I'm not going to spend time on something that makes no
significant difference.

If the people who are working with your programs are competent, a
few lint warnings will be easy enough for them to deal with. If
they are not, nothing you can do will make a bit of difference.

Followups have been directed to alt.flame.

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

gwyn@smoke.BRL.MIL (Doug Gwyn) (11/25/89)

In article <1989Nov23.233403.2841@twwells.com> bill@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.

Similar things could be said about most of these functions (the str*()
family being the exception, since they never report failure).

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.

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.

dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) (11/28/89)

In article <316@voa3.UUCP> ck@voa3.UUCP (Chris Kern) writes:
>But what about a standard library function whose value I
>(perhaps recklessly) wish to ignore?  Should I cast the function
>call to void, or am I just indulging in the trivial luxury of
>silencing lint?

I will crudely divide standard library functions into two groups, based
on their return value:

1.   Those that return a status value
2.   Those that return data

Many though not all of the standard I/O functions are in the first
category.  Most of the string functions are in the second category.
(There are some that return one or the other, e.g., returning either
data or EOF.  Handle with care.)

The return value from category 2 functions can usually be safely cast
to void.  This is quite common with strcpy, strcat, and similar
functions that return a pointer whose value you already have
elsewhere.  You are mainly accommodating the fact that what you needed
was a procedure but all you had was a function, and telling lint not to
remind you of this.

The return value from category 1 functions should be cast to void only
when you don't need the status value.  This takes more thought than
with category 2 functions.  Possibilities are:

a.   You were reading from or writing to an I/O stream, and you will
check for an error later (e.g. with ferror).  Most commonly you will do
a series of reads or writes without checking for an error each time,
and then finally test with ferror.

b.   There isn't much you can do about the error now, so you just give
up.  Very few people, for example, bother to check for an error
occurring on stderr after they have used fprintf to print an error
message to it.

c.   You *know* what the status code is going to be, so you don't check
it.  This usually arises out of careful analysis of your program, or
total recklessness.  In either case, be very suspicious.  I can't think
of many standard library functions that return a predictable status
code.

d.   Anything else that I missed.

Rahul Dhesi <dhesi%cirrusl@oliveb.ATC.olivetti.com>
UUCP:  oliveb!cirrusl!dhesi

flaps@dgp.toronto.edu (Alan J Rosenthal) (11/29/89)

dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) writes:
>I will crudely divide standard library functions into two groups, based
>on their return value:
>
>1.   Those that return a status value
>2.   Those that return data

...
>The return value from category 2 functions can usually be safely cast
>to void...

I don't think this is a very good taxonomy.  You should distinguish functions
that return interesting data from functions that return boring data.  Functions
like strcpy() that return boring data can be safely cast to void.  Functions
like atof() that return interesting data cannot.

ajr

--
"Learning algorithms from Knuth is almost as bad as learning physics from
 Newton in the Latin original."                     -- Jeffrey Kegler

bill@twwells.com (T. William Wells) (12/08/89)

In article <11680@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
: In article <1989Nov23.233403.2841@twwells.com> bill@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@twwells.com