[comp.lang.c] Check the Arg Count

brett@wjvax.UUCP (Brett Galloway) (01/06/87)

In article <1193@ucbcad.berkeley.edu> faustus@ucbcad.berkeley.edu (Wayne A. Christopher) writes:
>In article <4900@mimsy.UUCP>, mangoe@mimsy.UUCP (Charley Wingate) writes:
>> You still haven't explained why lint as a processor should be logically and
>> functionally distinct from cc as a processor.  The ONLY reason I can see for
>> separating them is so that you don't have to be confronted with messages
>> telling you that you're writng tricky or otherwise dubious code.
>
>Most of the things lint points out either aren't available to ccom, or
>are definitely not appropriate.  How is ccom going to know what is in
>the other files that I'm going to link with?  Detection of incompatible
>arguments, return values, etc across modules is lint's most useful
>function.

Wayne's first point is the strongest -- ccom CAN'T know anything about
source files outside of the one at hand.  Lint can.  I do, however, have
a gripe about lint (at least about 4.2bsd lint).  It provides the ability
to create lint libraries.  Unfortunately, lint treats these libraries
differently than cc treats object libraries.  It would be most useful for
maintaining large pieces of software if lint behaved the same as cc --
lint'ing source files into some intermediate form, finding all lint errors
unique to that source file (this is analogous to the compile cycle), and
lint'ing the intermediate lint files together to find global errors (this
is analogous to the load cycle).  This would make lint easier to
use, especially from within makefiles.  If lint were easier to use, it
might be used more extensively.

-- 
-------------
Brett Galloway
{pesnta,twg,ios,qubix,turtlevax,tymix,vecpyr,certes,isi}!wjvax!brett

donn@utah-gr.UUCP (Donn Seeley) (01/09/87)

Brett Galloway complains:

	...  [Lint] provides the ability to create lint libraries.
	Unfortunately, lint treats these libraries differently than cc
	treats object libraries.  It would be most useful for
	maintaining large pieces of software if lint behaved the same
	as cc -- lint'ing source files into some intermediate form,
	finding all lint errors unique to that source file (this is
	analogous to the compile cycle), and lint'ing the intermediate
	lint files together to find global errors (this is analogous to
	the load cycle).  This would make lint easier to use,
	especially from within makefiles. ...

Lint (under BSD Unix and probably most other varieties) works exactly
like cc, 'compiling' into an intermediate form and 'loading' the
result.  You can read the lint shell (/usr/bin/lint) to find out more
about how lint works.

It's really simple to build big lint libraries using a makefile to
avoid re-linting individual source files.  Try something like this:

------------------------------------------------------------------------
.SUFFIXES: .ln

.c.ln:
	lint -CTEMP $(LINTFLAGS) $*.c
	-mv llib-lTEMP.ln $@

CPPFLAGS=	-DDEBUG
LINTFLAGS=	-h $(CPPFLAGS)
CFLAGS=		-g $(CPPFLAGS)

OBJECTS=	fu.o bar.o
LINTINTS=	fu.ln bar.ln

all:	libfubar.a llib-lfubar.ln

libfubar.a:	$(OBJECTS)
	ar crv libfubar.a $(OBJECTS)

llib-lfubar.ln:	$(LINTINTS)
	cat $(LINTINTS) > llib-lfubar.ln
------------------------------------------------------------------------

This example causes lint files to be produced independently of object
files; if you so desired, you could change the '.c.o' rule
appropriately so that lint is always run when a file is recompiled.
Note that for a program rather than a library, you might write a
makefile line like 'lintall:; lint $(LINTFLAGS) $(LINTINTS)' instead
of using 'cat' to build a library.

Donn Seeley    University of Utah CS Dept    donn@cs.utah.edu
40 46' 6"N 111 50' 34"W    (801) 581-5668    utah-cs!donn

daveb@rtech.UUCP (Dave Brower) (01/09/87)

In article <1887@utah-gr.UUCP> donn@utah-gr.UUCP (Donn Seeley) writes:
>Brett Galloway complains:
>	...  [Lint] provides the ability to create lint libraries.
>	Unfortunately, lint treats these libraries differently than cc
>	treats object libraries.  It would be most useful for
>	maintaining large pieces of software if lint behaved the same
>	as cc -- lint'ing source files into some intermediate form,
>	finding all lint errors unique to that source file (this is
>	analogous to the compile cycle), and lint'ing the intermediate
>	lint files together to find global errors (this is analogous to
>	the load cycle).  This would make lint easier to use,
>	especially from within makefiles. ...
>
>Lint (under BSD Unix and probably most other varieties) works exactly
>like cc, 'compiling' into an intermediate form and 'loading' the
>result...

This is true in the simple case, and Donn's posted shell script will help
create libraries for those without the SV lint that has the -c option.

Unfortunately, the big problem is that lint libraries so conceived do
not have anywhere near the same semantics as the "equivalent" object
libraries.  Lint pass 2 can't selectivly load a module as is done by the
linker.  This can really complicate matters on large systems where many
executables are built from the same libraries without really using all
of the contents of the whole library.

Conjecture:

Would life be easier in this case if every .c file compiled into a library
had the magic /*LINTLIBRARY*/ comment?

-dB

-- 
	Kill Tree.	Kill Turkey.	Merry Xmas.

{amdahl, sun, mtxinu, cbosgd}!rtech!daveb

jpn@teddy.UUCP (John P. Nelson) (01/12/87)

In article <589@rtech.UUCP> daveb@rtech.UUCP (Dave Brower) writes:
>Unfortunately, the big problem is that lint libraries so conceived do
>not have anywhere near the same semantics as the "equivalent" object
>libraries.
>
> ...
>
>Would life be easier in this case if every .c file compiled into a library
>had the magic /*LINTLIBRARY*/ comment?

This helps quite a bit, but does not solve all the problems.  I modified
our lint to insert the /*LINTLIBRARY*/ comment into the stream of source
being used to generate the lint library - this is sort of like using -u
only on the lint library part of your lint run.  We have made LOTS of
other changes to our lint as well, so it would be hard to post a diff.

This does not solve various scoping problems:  For instance if I define
a static function write() in a library with different parameters than
the system write, I will get a lint cross-check error against llib-lc.ln


Here is the modified part of lint (originated as ULTRIX lint (BSD4.2)):
The relevant line used to be:

	*)      echo "$A:" ; (/lib/cpp $O $A | ${L}1 $X >>$T)2>&1

change this to:

	*)	echo "$A:"
		if [ "X$C" != X ]
		then
		    ((echo "/* LINTLIBRARY */" ; /lib/cpp $O $A) |
			${L}1 $X $U >>$T)2>&1
		else
		    (/lib/cpp $O $A | ${L}1 $X $U >>$T)2>&1
		fi

karl@haddock.UUCP (01/16/87)

[I've added comp.lang.c to the discussion.  --kwzh]
In article <5064@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
[Re the problem of type-checking on varargs functions]
>What is needed is a way of telling the compiler, `this routine takes
>arguments described by ...' that is general enough to cover printf, scanf,
>execl, and so forth, yet simple enough so that new ones can be introduced as
>necessary, and so that the syntax is not unduly cluttered.  The real problem
>is in conveying the `described by' part.  System V lint has /*PRINTFLIKE*/
>and /*SCANFLIKE*/ pragmas in its lint library, which takes care of printf and
>scanf and variants, but not execl.  Would adding /*REPEATING*/ suffice?  I
>cannot say.

Functions like execl(), which are variadic but not polymorphic, are the simple
case; adding /*REPEATING*/ and /*SENTINEL (char *)0*/ would be sufficient to
document these.*

Some functions switch on one arg to determine how to process the others.  (I
think these should be avoided in favor of separate functions when possible.)
These could be documented to lint as follows:
	/* SWITCHON 2 */
	int ioctl(int, TIOCNOTTY);
	int ioctl(int, TIOCGPGRP, int *);
	int ioctl(int, TIOCSPGRP, const int *);
	int ioctl(int, TIOCSTI, const char *);
However, this notation doesn't quite cover SysV open().

/*PRINTFLIKE*/, etc are a kludge; they require the syntax rules to be built
into the typechecker.  (The printf-like routine in adb, e.g., is excluded.)
To handle this in full generality would require something like an correctness-
proving language.  Fortunately, few variadic functions are of this type (and
the standard ones, as mentioned, are hard-coded).

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
*Along with /*SENTINEL*/, there should be another notation for functions whose
arg count is explicitly passed as one of the arguments.  Neither of these
would be necessary if C supported nargs().

gwyn@brl-smoke.ARPA (Doug Gwyn ) (01/17/87)

In article <305@haddock.UUCP> karl@haddock.ISC.COM.UUCP (Karl Heuer) writes:
>...  Neither of these would be necessary if C supported nargs().

"Number of arguments" is useless information without also being told
the types of the arguments.  The old UNIX implementations of nargs()
that I'm familiar with actually reported the number of words on the
stack used by parameters, not the actual number of parameters.  That
is even more useless.  I don't know how one could provide a logically
satisfactory specification for some such facility without imposing a
substantial overhead penalty on implementation of function linkage,
just to support a feature that most of us have gotten along perfectly
well without.

I know there are linkers that support dynamic binding etc. but the
point is we don't want to mandate such support on all conforming systems.