questions from using lint
Root Boy Jim
rbj at icst-cmr
Wed May 14 10:11:20 AEST 1986
> In article <501 at brl-smoke.ARPA> rbj at icst-cmr (Root Boy Jim) writes:
> >I have ranted about C using a one statement model for its control
> >statements instead of an explicit end statement. Compound statements are
> >bounded by braces instead. Yuk!
>
> Ah yes, there are two major types of language in the structured family;
> f77 with "endif" (some members use "end" for all of "endif", "endwhile",
> etc.) and pascal with "begin" "end" (which C abbreviates to "{" "}"). I
> presume this is what you dislike. (If it's the spelling that bothers you,
> I'm sure you're aware that you can define "begin" and "end" as macros.)
Well C certainly makes the spelling less verbose, but that is not my
complaint. The first structured language I came across (SIMPL-T at U of Md)
used the notation `IF <condition> THEN <list> { ELSE <list> } END'. This
has become my personal favorite paradigm for if statements. In fact, the
syntax of all control statements was almost entirely similar to that used
by the Bourne shell, except that END ended any kind of block.
This is superior to the `one statement' (braces, BEGIN-END, etc) style
because it explicitly delimits where the else statement goes. It is also
easier to parse.
> Yet another convention, not endorsed by any language I know, is to dispense
> with the braces and let the indentation alone tell the compiler how to
> interpret the program. (I came up with this idea after an argument on the
> "correct" place to put the braces.)
This is too scary, even for a scofflaw like myself. I don't trust
white space, and you give up the ability to `cb' or `indent' it.
> >Fortunately, there is the comma operator. This allows the following:
> > Most People Your's Truly
> > if (c) { if (c)
> > w = y; w = x,
> > y = z; y = z;
> > } /* look ma, no brace */
>
> I can hardly flame you for this, since I've used it myself when in a hurry.
> (But I write it on one line, "if (c) w=x, y=z"). I usually end up rewriting
> it with braces, though.
I often do myself. EMACS C-mode adds them for you automatically, so I
guess it's not much of an issue for some people.
> >Other things you will see in my code are:
> > exit((printf("usage: foo bar\n"),1));
> >or even: exit(1,printf("usage: foo bar\n"));
>
> What's wrong with
> printf("usage: foo bar\n"), exit(1);
> as above?
Oops, I goofed royally. BTW, I didn't notice that I needed the extra
parens in the first example until I posted it. Another example of why
not to use tricks. Silly rabbit :-)
> >Sufficeth to say that I use a lot of commas in my code. Unfortunately,
> >I cannot do this if either statement is a control struxure, *except* return.
> > Most People Your's Truly
> > if (c) { if (c)
> > w = y; return w = x,
> > return;
> > } /* look ma, no brace */
>
> You're introducing a minor inefficiency, since the compiler will have to
> copy the result of the last expression into the return register. I presume
> you don't bother to declare void functions "void", either, or this wouldn't
> make it past the compiler.
I hadn't even thought of that. In my defense I will have to mention
that 1) the expression may have already been computed in R0 anyway,
2) `tis a small matter, & 3) the attempt is to optimize cranial
time rather than execution time. The statements of the left side
are starting to get verbose, while the ones on the right side, especially
if written on one lline, are simple and to he point. It might take you
a bit to get used to the convention, but it's not that difficult.
As for void, it didn't exist on the compiler I first used. Even BSD
has problems with pointers to functions returning voids (did I get
it right?) so I avoid them. It is easier just to default it to
int, never return anything (or use my convention), and ignore the
value. That's right, easier, not better. I'm lazy. Generally, tho,
I find that I don't make *that* kind of mistake too often, so why
bother? It all comes down to what you gain versus what you put out,
and have to read for all eternity.
> >I cannot see *any* implementation doing either of the following:
> > 1) barfing because I returned an *extra* value sometimes
> > 2) barfing because I added an extra argument
>>
> You're probably correct in that all implementations that accept your code
> will produce correct results; however, I can easily imagine a compiler that
> would refuse to compile such an "obvious bug".
Not true. The first case is required to be supported so that I can ignore
a value (strcpy, eg) if I choose. The second is required to support printf.
> >Now you may claim that this is `bad programming practice', but I claim
> >that it is just a convention, just like #defines are usually capitalized.
> >You may not like either one, but I claim this is portable. And, it is
> >meaningful to me.
>
> But it *is* bad practice, in a measurable sense: you are using a style which
> is indistinguishable from a bug. As a result, you cannot easily use lint to
> find *real* bugs, because you've introduced so much noise in the lint output.
> You're throwing away a useful tool unnecessarily.
I see your point. I first ran lint after I had a few thousand lines of
code written, and it barfed unmercifully. Before that, I had attempted
to run it but the permission bits were set wrong for some files. Only
root could run it. By the time I figured out why, I had a bad taste in
my mouth. Also, reading the documentation left me unexcited. Maybe I will
give it another try someday. I'll probably point it at net.sources.
I find I can get along okay without it. That is my whole point. It's
not lint that bothers me, it's the people that think it's a panacea for
everything. Actually, I am pleased by the mixed reaction I received.
About half of the articles I've seen make this point as well.
I do prefer the way it fits into the language tho. It's there when you
need it but not shoved down your throat by run-time or compile-time checks.
> >I find it terribly ugly having to cast printf's or close's to void.
>
> Me too. But let's not lump all the cases together:
>
> [0] strcpy() returns a value that can be safely ignored. (Although I often
> find that I can use it in the next statement anyway.)
>
> [1] printf() returns a number which is normally pretty useless. It does also
> have an error return, but if you're writing to the terminal it's pretty
> safe to ignore that too. (Especially fprintf(stderr). What can you do
> if it fails, print an error message?)
>
> [2] close(), as near as I can tell, can only fail by being handed a number
> that does not denote an open file. I usually assume that this error
> would have been caught earlier.
I meant to say `fclose', which can write data and thus barf too.
> [3] unlink() and most other system calls should be checked! (It's too bad
> lint can't tell whether you've tested the return value of open(), etc.)
Mostly. But sometimes you don't care if the file you are trying to unlink
or the descriptor you are trying to close doesn't exist.
> My "solution" for [0]-[2] is simply to check the bottom of the lint output
> for "result ignored" messages, and decide which ones are serious. ("lint
> returns an error which is always ignored" :-)
Right. Grep -v helps here too.
> >And as someone pointed out, assignments return a value too, so should we
> >cast them to void as well? Oh yeah, assignment is `different'.
>
> Actually, this does bother me somewhat. I think I prefer the idea that
> values should be used or explicitly discarded, as in forth. (Not that forth
> has any error checking!) No, I'm not suggesting that lint should complain
> about assignments, or that C should have a different notation for assignments
> that are being pipelined into another expression. Just waiting for the next
> generation of languages.
The explicitness comes in the source code. Why do you find it so hard
to believe that I meant what I said?
> Karl W. Z. Heuer (ihnp4!bentley!kwh), The Walking Lint
(Root Boy) Jim Cottrell <rbj at cmr>
The Sitting Lint Maker
More information about the Comp.lang.c
mailing list