Subject: Re: ignoring return values from functions.
To: NetBSD Userlevel Technical Discussion List <tech-userlevel@netbsd.org>
From: Andrew Brown <atatat@atatdot.net>
List: tech-userlevel
Date: 09/20/2001 11:42:40
>> lint and the c compiler sometimes disagree.  some things, like the use
>> of NOTREACHED to aid lint in determining that a block of code is
>> ending seem bogus.  the c compiler knows, and the use of __dead can be
>> good thing.
>
>traditionally I've ignored the C compiler and only paid attention to
>lint because it was the only one which could be given hints like this in
>the past.

i've never used lint before now, although i'm willing to give it a go,
and i've just tried it on a small program.  complaints like this:

    sleep used( ioctl.c(98) ), but not defined
    wait used( ioctl.c(68) ), but not defined
    tcsetattr used( ioctl.c(138) ), but not defined
    err used( ioctl.c(69) ), but not defined
    tcgetattr used( ioctl.c(85) ), but not defined

i can do without.  the fact that lint complains than then exits with 0
also seems a little suspect to me.

>not to preach to the converted or anything, but perhaps this is an
>appropriate time to repeat some sage advice:
>
>           The Ten Commandments for C Programmers
>
>                       Henry Spencer
>
>1    Thou shalt run lint frequently and study its pronounce-
>     ments with care, for verily its perception  and  judge-
>     ment oft exceed thine.

this is one of those things that was written as humor.

>Also, for portable code I still find the lint-style hint comments to be
>infinitely more useful than any GCC-specific syntax (and even where ISO
>C approves, such stuff is still not portable and I won't use it).  GCC
>would do well to heed the lint-style hint comments if it's going to make
>lint-like complaints.

having to say ARGSUSED for a function like:

    static void
    sigchld(int nsig)
    {
        if (wait(NULL) == -1)
            err(1, "wait");
    }

strikes me as practically useless.  having to say NOTREACHED after
exit() also seems silly.  if lint was worth anything, if would be able
to tell that program flow stopped at that point and that the code
after it would not be reached.  putting in a comment to that effect
only disables the warning.  it doesn't make lint work any better.  in
fact, if i put code after the NOTREACHED, i would expect it to
complain that there's code i've said will never be reached.  it
doesn't.

>> i really don't think it helps the readability of the code.  then
>> again, if i wish to, i can make things much unreadable anyway by using
>> !! and -~ or ~-.
>
>It obviously depends on what you mean by "readability", and note more
>specifically that I also included "future maintainability" in there too!

the use of (void) adds visual clutter.  visual clutter detracts from
future maintainability.  it's more stuff someone has to wade through
to find the actual code.

>You seem to be implying that fewer words and syntactic glue is better.

less fluff is better.  i certainly don't expect anyone to use stuff
like

    for(;P("\n"),R-;P("|"))for(e=C;e-;P("_"+(*u++/8)%2))P("| "+(*u/4)%2);

or seriously use anything that appeared in an obfuscated c contest
entry, but c is not a language where one is expected to be overly
verbose with function and variable names in order to be expository.
likewise, the ultimate casting to void of anything that returns a
value (that's anything which does not already evaluate to void) seems
just a bit pedantic to me.

>I'm saying that explict delcaration of the programmer's intent is much
>better, even if it means using more words and syntactic glue.

then use blocks of comments.  don't clutter up the code.  if i call
close() or fclose(), i'm almost certainly going to ignore the return
value since if it failed, there's really very little i might do.
likewise, the following block of code

	void *v;
	int f;
	struct stat st;

	f = open("foo", O_RDONLY);
	fstat(f, &st);
	v = mmap(NULL, st.st_size, PROT_READ, MAP_FILE, f, 0);
	write(1, v, st.st_size);
	munmap(v, st.st_size);
	close(f);

could fail in all sorts of ways, but checking for return values when i
wrote it was just silly.  if any one call failed, all the following
calls could be expected to fail, and then i'd be done, regardless.
also consider that if the write fails, i still want to do the munmap()
and the close(), so just bailing out isn't terribly efficient.

>Again, the relevant quotes from Henry's advice column:
>
>3    Thou shalt cast all function arguments to the  expected
>     type  if  they  are not of that type already, even when
>     thou art convinced that this is unnecessary, lest  they
>     take  cruel  vengeance upon thee when thou least expect
>     it.
>
>6    If a function be advertised to return an error code  in
>     the  event  of  difficulties, thou shalt check for that
>     code, yea, even though the checks triple  the  size  of
>     thy  code  and produce aches in thy typing fingers, for
>     if thou thinkest ``it cannot happen to me'',  the  gods
>     shall surely punish thee for thy arrogance.

more humor.

-- 
|-----< "CODE WARRIOR" >-----|
codewarrior@daemon.org             * "ah!  i see you have the internet
twofsonet@graffiti.com (Andrew Brown)                that goes *ping*!"
andrew@crossbar.com       * "information is power -- share the wealth."