ok@edai.UUCP (Richard O'Keefe) (03/06/84)
The general problem with Lint is that the programs it is most needed
for are the ones it is least usable on. I've been trying to clean up a
moderately large (7500-line) C program recently, and the following
things have proven particularly annoying.
1. I am worried about portability of the program to 32-bit machines
whose C compiler defines int=short. I am told that the ONYX C
compiler for the Z8000 does this. I have carefully gone through the
program writing "long" everywhere it matters, and putting "int"
where it doesn't. But I didn't write the program. So I wanted Lint
to find the places I'd missed. And you'd think that the -a flag
would be exactly what you want. Indeed, the -a flag DID find
**one** place I'd missed, which could have had disastrous
consequences. BUT it also found over 50 other places, mostly of the
form
L =<< k;
where L had been declared long. (There were other things with the
same symptom but different etiologies.)
WANTED: an option which reports on "int" := "long" and NOTHING ELSE.
When I want to know about L =<< k, and I'm not silly enough to think
that I shouldn't check these, I would rather have another option for
that specific problem.
2. The program contains the following:
#include <stdio.h> /* defines NULL */
typedef long **ptr;
ptr foo;
baz(x)
ptr x;
{...}
... baz(NULL); ... foo = NULL; ... baz(foo); ...
Lint is perfectly happy with foo = NULL; but complains about the
"inconsistent usage" of baz's first argument. Given that K&R say
that 0 is an acceptable pointer of any type, I don't find this at
all helpful. This happens a lot in this particular program. What
I'm worried about is functions with an "int" argument being passed
"long" values, having to wade through some 34 bogus complaints of
this nature really doesn't help.
3. The program has been ported from a VAX to a PERQ running ICL's PaNiX
version of UNIX. PERQ pointers are normally to multiples of 16 bits,
so char* and short* have a different representation. It's also been
ported a machine whose normal addresses are long*. It *seems* to run
on these machines, but as development takes place on the VAX it would
be nice to check that future versions will port as well. So pointer
alignment problems are very interesting. The trouble is that I know
in advance that certain combinations will NOT cause problems on these
machines.
WANTED: a Lint declaration like /*ALIGNOK type1 type2*/
This declaration would mean that it is up to me to ensure that type1*
can safely be converted to type2*. An instance of what I mean is
typedef struct ugh
{
long a;
struct ugh *b;
} ugh, *ughp;
/*ALIGNOK long ugh*/
The idea is that you would start out with none of these declarations,
and Lint would find all the alignment problems it now reports. You'd
check through them, and you'd find some that were ok, so you'd add an
ALIGNOK declaration, and re-run Lint. You'd finally end up with just
the set of alignment assumptions you needed, and if you wanted to try
another machine, these declarations would tell you precisely which of
the many possible combinations your program relied on.
I have no access to the source of Lint. (We're running 4.1bsd.) Based on
what I know about compiling in general, it doesn't seem all that tough to
make these changes. Does anyone in netland know why it would be either
impossible or undesirable to do so? Better still, has someone got a Lint
we can copy that already has these or similar changes?
gwyn@brl-vgr.ARPA (Doug Gwyn ) (03/07/84)
When "lint" says that ptr = 0; is okay but func( 0 ) isn't where func() expects a pointer argument, you should believe it.
johanw@ttds.UUCP (Johan Wide'n) (03/08/84)
Another feature that would be nice to have in connection with braindamaged compilers with sizeof(int) != sizeof(char *) : Lint should tell you when the difference of two pointers is taken. (The result is an int.) To ensure portability we have been forced to hide the diff of pointers in a macro. For a 32-bit pointer, 16-bit int machine this macro casts the pointers into longs before taking the difference of them. This is not a completely satisfactory solution as the difference should indicate the number of objects between pointers, not just the number of bytes. We are fed up with this sort of compiler and now have two compilers on our MC68000-system. One compiler has 16-bit ints the other has 32-bit ints. The 16-bit compiler can be used for showing of benchmarks, the 32-bit is useful for porting programs to the MC68000. Use of the 32-bit compiler requires that one links the programs not with libc but a modified version of libc with rewritten systemcalls. That is: the routine write.s which traps to the write system call must be changed to take account of the fact that it's arguments are write(32-bit, (char *), 32-bit); whereas the system expects write(16-bit, (char *), 16-bit); {decvax,philabs}!mcvax!enea!ttds!johanw Johan Widen
keesan@bbncca.ARPA (Morris Keesan) (03/09/84)
---------------------------- ok@edai complains: > #include <stdio.h> /* defines NULL */ > typedef long **ptr; > ptr foo; > baz(x) > ptr x; > {...} > ... baz(NULL); ... foo = NULL; ... baz(foo); ... > > Lint is perfectly happy with foo = NULL; but complains about the > "inconsistent usage" of baz's first argument. Given that K&R say > that 0 is an acceptable pointer of any type, I don't find this at > all helpful. Lint is behaving in a perfectly legitimate way here, and is being very helpful in pointing out a portability problem. We've been through all of this very recently in this newsgroup. K&R do NOT say that "0 is an acceptable pointer". What is said about 0 and pointers in the C Reference Manual (Appendix A of K&R) is: 7.7 Equality operators [p. 190] . . . A pointer to which 0 has been assigned is guaranteed not to point to any object, and will APPEAR to be equal to 0; in conventional usage, such a pointer is considered to be null. [UPPER CASE mine] [This means that 0 can act like a pointer with the == and != operators] 7.14 Assignment operators [p. 192] . . . it is guaranteed that assignment of the constant 0 to a pointer will produce a null pointer distinguishable from a pointer to any object. [end of citations from Reference Manual] What you should be doing to shut lint up is casting NULL to the right type of pointer, e.g. baz((ptr)NULL); If you don't want to do this, then you want features added to lint by which you can declare something like /* COMPATIBLE int ptr */, which would document the assumption being made, or you could define NULL as ((char *)0), and then issue an /*ALIGNOK *ptr char*/ as per your following suggestion. -- Morris M. Keesan {decvax,linus,wjh12,ima}!bbncca!keesan keesan @ BBN-UNIX.ARPA