[net.lang.c] Bellybutton lint

ptw (04/09/83)

     What flag would one use with (4.1) lint to get it to tell you that

		char *string = input;

		for(; string != '\0'; string++)

is an error?  Seems to me that a character constant should not be allowed to
be compared to a pointer.

			     P. Tucker Withington
			     Automatix Incorporated
			     ...decvax!{wivax,genrad}!linus!vaxine!ptw
			     (617) 667-7900 x2044

donn (04/10/83)

Reference: vaxine.115

	What flag would one use with (4.1) lint to get it to tell you that

			char *string = input;

			for(; string != '\0'; string++)

	is an error?  Seems to me that a character constant should not
	be allowed to be compared to a pointer.

				     P. Tucker Withington
				     Automatix Incorporated
				     ...decvax!{wivax,genrad}!linus!vaxine!ptw
				     (617) 667-7900 x2044

This is a tricky one.  The problem is that in general character
constants may NOT be compared to pointers -- in fact the only things
that may legally be compared to pointers are other pointers and the
integer 0 (C Reference Manual, Sections 7.6, 7.7).  But the relational
expression in the example is in fact testing the pointer "string"
against the integer 0, since characters are promoted to integers in
relational expressions (7.7); we don't have a type clash.  You might
expect at least a warning from the PCC or lint, however.

Well, it turns out that the PCC is too clever.  Since character values
are always promoted to integer values in expressions, the PCC doesn't
bother to save type information about character constants; they are
treated as another way of expressing integers.  (It's easy to see why
this is done when you remember that multi-character character constants
are permitted by the PCC.  Notice that this is NOT in the standard.) By
the time the error is reportable (routine chkpun() in trees.c) there is
no way to tell that the user put '\0' instead of 0.  Lint just re-uses
the PCC code and thus it couldn't say anything useful about style or
programming heuristics even if it wanted to.

The only consolation is that this only happens when you are trying to
compare with '\0'; any other character value would cause a warning.

Donn Seeley  UCSD Chemistry Dept. RRCF  ucbvax!sdcsvax!sdchema!donn
             (619) 452-4016             sdamos!donn@nprdc

thomas (04/14/83)

4.1 lint complains about 0 not matching pointers on function calls, but
nowhere else.  This is weird!

=Spencer

ark (04/15/83)

The comment was that lint complains about 0 not matching pointers
in function calls but not elsewhere.  This is correct.  Consider:

	sometype *foo;
	foo = 0;

The assignment has the same effect as

	foo = (sometype *) 0;

0 is guaranteed to be convertible to a pointer, and it is guaranteed
that this resulting pointer will compare unequal to a pointer to any
actual data object.  The cast is unnecessary because the right hand
side of an assignment is what some people call a "strong context":
there is only one type that is legitimate in that context.

Now consider:

	f(0)

It is not possible, in general, to determine by inspection what type
f expects unless the definition of f is handy.  Suppose that f is:

	f (x) sometype *x; {...}

and that it is compiled elsewhere.  Now, an integer is being passed,
WITHOUT CONVERSION, to a function that expects a pointer.

You may say: So what?  Won't some kind of implicit conversion take place?
Well, maybe.  On some machines, it is convenient to have 16-bit integers
and 32-bit pointers.  Saying f(0) definitely won't work on these machines;
you must say

	f((sometype *) 0)

instead.  In C, an actual parameter is not a strong context.

lantz (04/23/83)

    I've always wondered why NULL isn't defined in stdio as ((char *)0).
Is there some good reason, or is just because on most systems it isn't
necessary?
    This would make the call
	execl("whatever", "whatever", NULL);
correct regardless of the relative sizes of integers and pointers.

					Philip Lantz
					duke!ucf-cs!lantz

guy (04/24/83)

If it were defined that way, if you had a routine "foo":

foo(bar)
int *bar;
{
	if (bar == NULL)
		do one thing;
	else
		do another;
}

and you wanted to call "foo" with a null pointer, you would either have to
say

	foo((int *)0);

or say

	foo(NULL);

in which case "lint" would bitch that you were passing a "char *" to a
routine that expected an "int *", or say

	foo((int *)NULL);

in which case "lint" would bitch that you were trying to convert a "char *"
to an "int *" which is a Bozo No-No.  Trouble is there *is* no such thing
as a "null pointer" in C; there is a null character pointer, and a null
int pointer, and a null struct proc pointer, and a null int() pointer, and...

					Guy Harris
					RLG Corporation
					{seismo,mcnc,we13}!rlgvax!guy