MirOS Manual: 22.lint(PSD)


                 Lint, a C Program Checker

                       S. C. Johnson

                          ABSTRACT

          Lint is a command  which  examines  C  source
     programs,  detecting a number of bugs and obscuri-
     ties.  It  enforces  the  type  rules  of  C  more
     strictly than the C compilers. It may also be used
     to enforce a number  of  portability  restrictions
     involved  in  moving  programs  between  different
     machines and/or operating systems. Another  option
     detects a number of wasteful, or error prone, con-
     structions which nevertheless are, strictly speak-
     ing, legal.

          Lint accepts multiple input files and library
     specifications, and checks them for consistency.

          The separation of function between  lint  and
     the  C compilers has both historical and practical
     rationale. The compilers turn C programs into exe-
     cutable  files  rapidly  and  efficiently. This is
     possible in part because the compilers do  not  do
     sophisticated  type  checking,  especially between
     separately compiled programs. Lint  takes  a  more
     global,  leisurely  view  of  the program, looking
     much more carefully at the compatibilities.

          This document  discusses  the  use  of  lint,
     gives an overview of the implementation, and gives
     some hints on the writing of machine independent C
     code.

Introduction and Usage

     Suppose there are two C[1] source  files,  file1.c  and
file2.c,  which are ordinarily compiled and loaded together.
Then the command

        lint  file1.c  file2.c

produces messages describing inconsistencies and inefficien-
cies  in the programs. The program enforces the typing rules

PS1:9-2                            Lint, a C Program Checker

of C more strictly than the C compilers (for both historical
and practical reasons) enforce them. The command

        lint  -p  file1.c  file2.c

will produce, in addition to the above messages,  additional
messages  which relate to the portability of the programs to
other operating systems and machines. Replacing the -p by -h
will  produce messages about various error-prone or wasteful
constructions which, strictly speaking, are not bugs. Saying
-hp gets the whole works.

     The next several sections describe the major  messages;
the document closes with sections discussing the implementa-
tion and giving  suggestions  for  writing  portable  C.  An
appendix gives a summary of the lint options.

A Word About Philosophy

     Many of the facts which lint needs may be impossible to
discover. For example, whether a given function in a program
ever gets called may depend  on  the  input  data.  Deciding
whether  exit  is  ever  called is equivalent to solving the
famous ``halting problem,'' known to be recursively undecid-
able.

     Thus, most of the lint algorithms are a compromise.  If
a  function is never mentioned, it can never be called. If a
function is mentioned, lint assumes it can be  called;  this
is not necessarily so, but in practice is quite reasonable.

     Lint tries to give information with a  high  degree  of
relevance.  Messages  of the form ``xxx might be a bug'' are
easy to generate, but are acceptable only in  proportion  to
the  fraction of real bugs they uncover. If this fraction of
real bugs is too small, the messages lose their  credibility
and  serve  merely  to  clutter up the output, obscuring the
more important messages.

     Keeping these issues in mind, we now consider  in  more
detail the classes of messages which lint produces.

Unused Variables and Functions

     As sets of programs evolve and develop, previously used
variables  and  arguments to functions may become unused; it
is not uncommon for external variables, or even entire func-
tions,  to  become  unnecessary, and yet not be removed from
the source. These  ``errors  of  commission''  rarely  cause
working  programs  to fail, but they are a source of ineffi-
ciency, and make programs harder to understand  and  change.
Moreover,  information about such unused variables and func-
tions can occasionally serve to discover bugs; if a function
does  a  necessary  job,  and  is never called, something is

Lint, a C Program Checker                            PS1:9-3

wrong!

     Lint complains about variables and functions which  are
defined  but  not otherwise mentioned. An exception is vari-
ables which are declared through explicit extern  statements
but are never referenced; thus the statement

        extern  float  sin();

will evoke no comment if sin is never used. Note  that  this
agrees  with the semantics of the C compiler. In some cases,
these  unused  external  declarations  might  be   of   some
interest;  they  can  be discovered by adding the -x flag to
the lint invocation.

     Certain styles of programming require many functions to
be  written with similar interfaces; frequently, some of the
arguments may be unused in many of the calls. The -v  option
is  available  to  suppress the printing of complaints about
unused arguments. When -v is in effect, no messages are pro-
duced  about  unused  arguments  except  for those arguments
which are unused and also declared  as  register  arguments;
this  can be considered an active (and preventable) waste of
the register resources of the machine.

     There is one case where information  about  unused,  or
undefined,  variables is more distracting than helpful. This
is when lint is applied to some, but not all, files out of a
collection  which  are  to be loaded together. In this case,
many of the functions and variables defined may not be used,
and,  conversely, many functions and variables defined else-
where may be used. The -u flag may be used to  suppress  the
spurious messages which might otherwise appear.

Set/Used Information

     Lint attempts to detect cases where a variable is  used
before  it  is  set. This is very difficult to do well; many
algorithms take a good deal of time  and  space,  and  still
produce   messages  about  perfectly  valid  programs.  Lint
detects local  variables  (automatic  and  register  storage
classes)  whose  first use appears physically earlier in the
input file than the first assignment  to  the  variable.  It
assumes  that taking the address of a variable constitutes a
``use,'' since the actual use may occur at any  later  time,
in a data dependent fashion.

     The restriction to the physical appearance of variables
in  the  file  makes  the algorithm very simple and quick to
implement, since the  true  flow  of  control  need  not  be
discovered.  It  does mean that lint can complain about some
programs which are legal, but these programs would  probably
be  considered  bad on stylistic grounds (e.g. might contain
at least two goto's). Because static and external  variables

PS1:9-4                            Lint, a C Program Checker

are  initialized  to  0,  no  meaningful  information can be
discovered about their uses. The algorithm deals  correctly,
however, with initialized automatic variables, and variables
which are used in the expression which first sets them.

     The set/used information also  permits  recognition  of
those  local  variables  which are set and never used; these
form a frequent source of inefficiencies, and  may  also  be
symptomatic of bugs.

Flow of Control

     Lint attempts to detect  unreachable  portions  of  the
programs  which  it  processes. It will complain about unla-
beled statements immediately  following  goto,  break,  con-
tinue,  or  return  statements. An attempt is made to detect
loops which can never be left at the bottom,  detecting  the
special cases while( 1 ) and for(;;) as infinite loops. Lint
also complains about loops which cannot be  entered  at  the
top;  some  valid  programs may have such loops, but at best
they are bad style, at worst bugs.

     Lint has an important area of blindness in the flow  of
control  algorithm:  it  has  no  way of detecting functions
which are called and never return. Thus, a call to exit  may
cause  unreachable code which lint does not detect; the most
serious effects of this are in the determination of returned
function values (see the next section).

     One form of unreachable statement is not  usually  com-
plained  about  by  lint;  a  break statement that cannot be
reached causes no message. Programs  generated  by  yacc,[2]
and  especially  lex,[3]  may  have  literally  hundreds  of
unreachable break statements. The -O flag in the C  compiler
will often eliminate the resulting object code inefficiency.
Thus, these unreached statements are of  little  importance,
there  is  typically nothing the user can do about them, and
the resulting messages would clutter up the lint output.  If
these  messages are desired, lint can be invoked with the -b
option.

Function Values

     Sometimes functions return values which are never used;
sometimes programs incorrectly use function ``values'' which
have never been returned. Lint addresses this problem  in  a
number of ways.

     Locally, within a function definition,  the  appearance
of both

        return(  expr  );

and

Lint, a C Program Checker                            PS1:9-5

        return ;

statements is cause for alarm; lint will give the message

        function name contains return(e) and return

The most serious difficulty with this is  detecting  when  a
function  return  is implied by flow of control reaching the
end of the function. This can be seen with a simple example:

        f ( a ) {
             if ( a ) return ( 3 );
             g ();
             }

Notice that, if a tests false, f will call g and then return
with  no defined return value; this will trigger a complaint
from lint. If g, like exit, never returns, the message  will
still be produced when in fact nothing is wrong.

     In practice, some potentially serious  bugs  have  been
discovered  by this feature; it also accounts for a substan-
tial fraction of the ``noise'' messages produced by lint.

     On a global scale, lint detects cases where a  function
returns  a  value,  but  this value is sometimes, or always,
unused. When the value is always unused, it  may  constitute
an  inefficiency  in the function definition. When the value
is sometimes unused, it may represent bad style  (e.g.,  not
testing for error conditions).

     The dual problem, using a function value when the func-
tion  does not return one, is also detected. This is a seri-
ous problem. Amazingly, this bug has been observed on a cou-
ple  of occasions in ``working'' programs; the desired func-
tion value just happened to have been computed in the  func-
tion return register!

Type Checking

     Lint  enforces  the  type  checking  rules  of  C  more
strictly  than  the compilers do. The additional checking is
in four major areas: across  certain  binary  operators  and
implied  assignments,  at the structure selection operators,
between the definition and uses of functions, and in the use
of enumerations.

     There are a number of operators which have  an  implied
balancing  between  types  of  the operands. The assignment,
conditional ( ?: ), and relational operators have this  pro-
perty;  the  argument of a return statement, and expressions
used in initialization also suffer similar  conversions.  In
these  operations,  char, short, int, long, unsigned, float,

PS1:9-6                            Lint, a C Program Checker

and double types may be  freely  intermixed.  The  types  of
pointers  must agree exactly, except that arrays of x's can,
of course, be intermixed with pointers to x's.

     The type checking rules also require that, in structure
references,  the  left  operand  of  the  -> be a pointer to
structure, the left operand of the . be a structure, and the
right  operand  of these operators be a member of the struc-
ture implied by the left operand. Similar checking  is  done
for references to unions.

     Strict rules apply  to  function  argument  and  return
value  matching.  The  types  float and double may be freely
matched, as may the types char, short,  int,  and  unsigned.
Also,  pointers  can  be matched with the associated arrays.
Aside from this, all actual arguments  must  agree  in  type
with their declared counterparts.

     With enumerations, checks  are  made  that  enumeration
variables  or  members  are  not  mixed with other types, or
other enumerations, and that the only operations applied are
=, initialization, ==, !=, and function arguments and return
values.

Type Casts

     The type cast feature in C was introduced largely as an
aid  to  producing  more  portable  programs.  Consider  the
assignment

        p = 1 ;

where p is a character pointer. Lint will quite rightly com-
plain. Now, consider the assignment

        p = (char *)1 ;

in which a cast has been used to convert the  integer  to  a
character  pointer.  The  programmer  obviously had a strong
motivation for doing this,  and  has  clearly  signaled  his
intentions.  It seems harsh for lint to continue to complain
about this. On the other hand, if  this  code  is  moved  to
another  machine,  such  code should be looked at carefully.
The -c flag controls the printing of comments  about  casts.
When  -c is in effect, casts are treated as though they were
assignments subject to complaint; otherwise, all legal casts
are  passed  without comment, no matter how strange the type
mixing seems to be.

Nonportable Character Use

     On the PDP-11, characters are signed quantities, with a
range  from  -128 to 127. On most of the other C implementa-
tions, characters take on only positive values.  Thus,  lint

Lint, a C Program Checker                            PS1:9-7

will flag certain comparisons and assignments as being ille-
gal or nonportable. For example, the fragment

        char c;
                ...
        if( (c = getchar()) < 0 ) ....

works on the PDP-11, but will fail on machines where charac-
ters always take on positive values. The real solution is to
declare c an integer, since getchar  is  actually  returning
integer  values.  In  any  case, lint will say ``nonportable
character comparison''.

     A similar issue arises with bitfields; when assignments
of  constant  values are made to bitfields, the field may be
too small to hold the value. This is especially true because
on  some machines bitfields are considered as signed quanti-
ties. While it may seem unintuitive to consider that  a  two
bit  field declared of type int cannot hold the value 3, the
problem disappears if the bitfield is declared to have  type
unsigned.

Assignments of longs to ints

     Bugs may arise from the assignment of long to  an  int,
which loses accuracy. This may happen in programs which have
been incompletely converted to use typedefs. When a  typedef
variable  is  changed from int to long, the program can stop
working because some intermediate results may be assigned to
ints,  losing  accuracy. Since there are a number of legiti-
mate reasons for assigning longs to ints, the  detection  of
these assignments is enabled by the -a flag.

Strange Constructions

     Several perfectly legal,  but  somewhat  strange,  con-
structions  are  flagged  by  lint;  the  messages hopefully
encourage better code quality, clearer style, and  may  even
point  out bugs. The -h flag is used to enable these checks.
For example, in the statement

        *p++ ;

the  *  does  nothing;  this  provokes  the  message  ``null
effect'' from lint. The program fragment

        unsigned x ;
        if( x < 0 ) ...

is clearly somewhat strange; the test  will  never  succeed.
Similarly, the test

        if( x > 0 ) ...

PS1:9-8                            Lint, a C Program Checker

is equivalent to

        if( x != 0 )

which may not be the intended action. Lint will say ``degen-
erate unsigned comparison'' in these cases. If one says

        if( 1 != 0 ) ....

lint will report ``constant in conditional context'',  since
the comparison of 1 with 0 gives a constant result.

     Another construction detected by lint involves operator
precedence.  Bugs  which  arise from misunderstandings about
the precedence of operators can be  accentuated  by  spacing
and formatting, making such bugs extremely hard to find. For
example, the statements

        if( x&077 == 0 ) ...

or

        x<<2 + 40

probably do not do what was intended. The best  solution  is
to  parenthesize  such expressions, and lint encourages this
by an appropriate message.

     Finally, when the -h flag is in  force  lint  complains
about  variables  which  are redeclared in inner blocks in a
way that conflicts with their use in outer blocks.  This  is
legal,  but  is considered by many (including the author) to
be bad style, usually unnecessary, and frequently a bug.

Ancient History

     There are several forms of older syntax which are being
officially discouraged. These fall into two classes, assign-
ment operators and initialization.

     The older forms of assignment operators (e.g., =+,  =-,
. . . ) could cause ambiguous expressions, such as

        a  =-1 ;

which could be taken as either

        a =-  1 ;

or

        a  =  -1 ;

The situation is  especially  perplexing  if  this  kind  of

Lint, a C Program Checker                            PS1:9-9

ambiguity  arises as the result of a macro substitution. The
newer, and preferred operators (+=, -=, etc. ) have no  such
ambiguities.  To  spur  the  abandonment of the older forms,
lint complains about these old fashioned operators.

     A similar issue arises with initialization.  The  older
language allowed

        int  x  1 ;

to initialize x to 1. This also caused  syntactic  difficul-
ties: for example,

        int  x  ( -1 ) ;

looks somewhat like the beginning of a function declaration:

        int  x  ( y ) {  . . .

and the compiler must read a fair ways past x  in  order  to
sure  what the declaration really is.. Again, the problem is
even more perplexing when the initializer involves a  macro.
The  current  syntax places an equals sign between the vari-
able and the initializer:

        int  x  =  -1 ;

This is free of any possible syntactic ambiguity.

Pointer Alignment

     Certain pointer assignments may be reasonable  on  some
machines,  and  illegal on others, due entirely to alignment
restrictions. For example, on the PDP-11, it  is  reasonable
to  assign integer pointers to double pointers, since double
precision values may begin on any integer boundary.  On  the
Honeywell  6000,  double precision values must begin on even
word boundaries; thus, not all such assignments make  sense.
Lint  tries  to  detect cases where pointers are assigned to
other pointers, and such alignment problems might arise. The
message  ``possible pointer alignment problem'' results from
this situation whenever either the -p or  -h  flags  are  in
effect.

Multiple Uses and Side Effects

     In complicated expressions, the best order in which  to
evaluate subexpressions may be highly machine dependent. For
example, on machines (like the PDP-11) in  which  the  stack
runs  backwards,  function  arguments  will probably be best
evaluated from right-to-left; on machines with a stack  run-
ning  forward, left-to-right seems most attractive. Function
calls embedded as arguments of other functions  may  or  may
not  be  treated  similarly  to  ordinary arguments. Similar

PS1:9-10                           Lint, a C Program Checker

issues arise with other operators which have  side  effects,
such  as  the  assignment  operators  and  the increment and
decrement operators.

     In order that the  efficiency  of  C  on  a  particular
machine not be unduly compromised, the C language leaves the
order of evaluation of complicated  expressions  up  to  the
local  compiler,  and, in fact, the various C compilers have
considerable differences in the order  in  which  they  will
evaluate  complicated  expressions.  In  particular,  if any
variable is changed by a side effect, and  also  used  else-
where in the same expression, the result is explicitly unde-
fined.

     Lint checks for the important special case where a sim-
ple scalar variable is affected. For example, the statement

        a[i] = b[i++] ;

will draw the complaint:

        warning: i evaluation order undefined

Implementation

     Lint consists of two programs and a driver.  The  first
program  is  a version of the Portable C Compiler[4,5] which
is the basis of the IBM 370, Honeywell 6000,  and  Interdata
8/32  C  compilers.  This  compiler  does lexical and syntax
analysis on the input text, constructs and maintains  symbol
tables, and builds trees for expressions. Instead of writing
an intermediate file which is passed to a code generator, as
the  other  compilers do, lint produces an intermediate file
which consists of lines of ascii text. Each line contains an
external  variable name, an encoding of the context in which
it was seen (use, definition,  declaration,  etc.),  a  type
specifier,  and  a  source  file  name  and line number. The
information about variables local to a function or  file  is
collected  by  accessing the symbol table, and examining the
expression trees.

     Comments about local problems are produced as detected.
The  information  about  external names is collected onto an
intermediate file. After all the source  files  and  library
descriptions  have  been collected, the intermediate file is
sorted to bring all  information  collected  about  a  given
external  name  together.  The second, rather small, program
then reads the lines from the intermediate file and compares
all  of  the  definitions,  declarations,  and uses for con-
sistency.

     The driver controls this process, and is also responsi-
ble for making the options available to both passes of lint.

Lint, a C Program Checker                           PS1:9-11

Portability

     C on the Honeywell and IBM systems is used, in part, to
write  system code for the host operating system. This means
that the implementation of C tends to follow  local  conven-
tions rather than adhere strictly to  UNIX-  system  conven-
tions.  Despite these differences, many C programs have been
successfully moved to GCOS and the various IBM installations
with  little  effort.  This  section  describes  some of the
differences between the implementations, and  discusses  the
lint features which encourage portability.

     Uninitialized  external  variables  are  treated   dif-
ferently  in  different  implementations  of  C. Suppose two
files both contain  a  declaration  without  initialization,
such as

        int a ;

outside of any function. The UNIX loader will resolve  these
declarations,  and cause only a single word of storage to be
set aside for a. Under the  GCOS  and  IBM  implementations,
this  is  not feasible (for various stupid reasons!) so each
such declaration causes a word of storage to  be  set  aside
and  called  a. When loading or library editing takes place,
this causes fatal conflicts which prevent the proper  opera-
tion of the program. If lint is invoked with the -p flag, it
will detect such multiple definitions.

     A related difficulty comes from the amount of  informa-
tion  retained  about external names during the loading pro-
cess. On the UNIX system, externally known names have  seven
significant  characters,  with the upper/lower case distinc-
tion kept. On the IBM systems, there are  eight  significant
characters, but the case distinction is lost. On GCOS, there
are only six characters, of a single  case.  This  leads  to
situations  where  programs  run  on  the  UNIX  system, but
encounter loader problems on the IBM or GCOS  systems.  Lint
-p  causes all external symbols to be mapped to one case and
truncated  to  six  characters,   providing   a   worst-case
analysis.

     A number of differences arise in the area of  character
handling: characters in the UNIX system are eight bit ascii,
while they are eight bit ebcdic on the  IBM,  and  nine  bit
ascii  on  GCOS. Moreover, character strings go from high to
low bit positions (``left to right'') on GCOS and  IBM,  and
low  to  high  (``right to left'') on the PDP-11. This means
that code attempting to construct strings out  of  character
constants,  or  attempting to use characters as indices into
_________________________
- UNIX is a registered trademark of AT&T  Bell  Labora-
tories in the USA and other countries.

PS1:9-12                           Lint, a C Program Checker

arrays, must be looked at with great suspicion. Lint  is  of
little  help  here, except to flag multi-character character
constants.

     Of course, the word sizes are  different!  This  causes
less  trouble  than  might be expected, at least when moving
from the UNIX system (16 bit words) to the IBM (32 bits)  or
GCOS  (36  bits).  The  main problems are likely to arise in
shifting or masking. C now supports  a  bit-field  facility,
which can be used to write much of this code in a reasonably
portable way. Frequently, portability of such  code  can  be
enhanced  by  slight rearrangements in coding style. Many of
the incompatibilities seem to have the flavor of writing

        x &= 0177700 ;

to clear the low order six bits of x. This suffices  on  the
PDP-11,  but  fails  badly on GCOS and IBM. If the bit field
feature cannot be used, the same effect can be  obtained  by
writing

        x &= ~ 077 ;

which will work on all these machines.

     The right shift operator is  arithmetic  shift  on  the
PDP-11,  and logical shift on most other machines. To obtain
a logical shift on all machines, the  left  operand  can  be
typed unsigned. Characters are considered signed integers on
the PDP-11, and unsigned on the other  machines.  This  per-
sistence  of the sign bit may be reasonably considered a bug
in the PDP-11 hardware which has infiltrated itself into the
C  language.  If  there were a good way to discover the pro-
grams which would be affected, C could be  changed;  in  any
case, lint is no help here.

     The above discussion may have made the problem of  por-
tability seem bigger than it in fact is. The issues involved
here are rarely subtle or mysterious, at least to the imple-
mentor  of  the program, although they can involve some work
to straighten out. The most serious bar to  the  portability
of  UNIX  system  utilities  has been the inability to mimic
essential UNIX system functions on the  other  systems.  The
inability  to  seek to a random character position in a text
file, or to establish a pipe between processes, has involved
far more rewriting and debugging than any of the differences
in C compilers. On the other hand, lint has been very  help-
ful in moving the UNIX operating system and associated util-
ity programs to other machines.

Shutting Lint Up

     There are occasions when the programmer is smarter than
lint. There may be valid reasons for ``illegal'' type casts,

Lint, a C Program Checker                           PS1:9-13

functions with a variable number of  arguments,  etc.  More-
over,  as  specified  above, the flow of control information
produced by lint often has blind spots,  causing  occasional
spurious messages about perfectly reasonable programs. Thus,
some way of communicating with lint, typically  to  shut  it
up, is desirable.

     The form which this mechanism should take is not at all
clear.  New keywords would require current and old compilers
to recognize these keywords, if only to  ignore  them.  This
has  both  philosophical and practical problems. New prepro-
cessor syntax suffers from similar problems.

     What was finally done was to cause a number of words to
be  recognized  by lint when they were embedded in comments.
This required minimal preprocessor changes; the preprocessor
just  had  to  agree to pass comments through to its output,
instead of deleting them as had been previously done.  Thus,
lint  directives  are  invisible  to  the compilers, and the
effect on systems with the  older  preprocessors  is  merely
that the lint directives don't work.

     The first directive is concerned with flow  of  control
information;  if a particular place in the program cannot be
reached, but this is not  apparent  to  lint,  this  can  be
asserted by the directive

        /* NOTREACHED */

at the appropriate spot in the program. Similarly, if it  is
desired  to  turn  off  strict  type  checking  for the next
expression, the directive

        /* NOSTRICT */

can be used; the situation reverts to the  previous  default
after  the next expression. The -v flag can be turned on for
one function by the directive

        /* ARGSUSED */

Complaints about variable number of arguments in calls to  a
function can be turned off by the directive

        /* VARARGS */

preceding the function definition.  In  some  cases,  it  is
desirable  to  check  the first several arguments, and leave
the later arguments unchecked. This can be done by following
the  VARARGS  keyword  immediately  with  a digit giving the
number of arguments which should be checked; thus,

        /* VARARGS2 */

PS1:9-14                           Lint, a C Program Checker

will cause the first two arguments to be checked, the others
unchecked. Finally, the directive

        /* LINTLIBRARY */

at the head of a file identifies  this  file  as  a  library
declaration file; this topic is worth a section by itself.

Library Declaration Files

     Lint accepts certain library directives, such as

        -ly

and tests the source  files  for  compatibility  with  these
libraries.  This  is  done  by accessing library description
files whose names are constructed from  the  library  direc-
tives. These files all begin with the directive

        /* LINTLIBRARY */

which is followed by a series of dummy function definitions.
The  critical parts of these definitions are the declaration
of the function return  type,  whether  the  dummy  function
returns  a  value,  and the number and types of arguments to
the function. The VARARGS and  ARGSUSED  directives  can  be
used to specify features of the library functions.

     Lint library files are processed  almost  exactly  like
ordinary source files. The only difference is that functions
which are defined on a library file, but are not used  on  a
source  file,  draw  no complaints. Lint does not simulate a
full library search algorithm, and complains if  the  source
files contain a redefinition of a library routine (this is a
feature!).

     By default,  lint  checks  the  programs  it  is  given
against a standard library file, which contains descriptions
of the programs which are normally loaded when a  C  program
is  run.  When  the  -p  flag  is in effect, another file is
checked containing descriptions of the standard I/O  library
routines  which  are  expected to be portable across various
machines. The -n flag can be used to  suppress  all  library
checking.

Bugs, etc.

     Lint  was  a  difficult  program  to  write,  partially
because  it is closely connected with matters of programming
style, and partially because users usually don't notice bugs
which cause lint to miss errors which it should have caught.
(By contrast, if lint incorrectly complains about  something
that is correct, the programmer reports that immediately!)

Lint, a C Program Checker                           PS1:9-15

     A number of areas remain to be further  developed.  The
checking of structures and arrays is rather inadequate; size
incompatibilities go unchecked, and no attempt  is  made  to
match up structure and union declarations across files. Some
stricter checking of the  use  of  the  typedef  is  clearly
desirable,  but  what  checking  is  appropriate, and how to
carry it out, is still to be determined.

     Lint shares the preprocessor with the  C  compiler.  At
some  point  it  may be appropriate for a special version of
the preprocessor to be constructed which checks  for  things
such as unused macro definitions, macro arguments which have
side effects which are not expanded at all, or are  expanded
more than once, etc.

     The central problem with lint is the packaging  of  the
information  which it collects. There are many options which
serve  only  to  turn  off,  or  slightly  modify,   certain
features.  There  are  pressures  to  add even more of these
options.

     In conclusion, it appears that the  general  notion  of
having two programs is a good one. The compiler concentrates
on quickly and accurately turning the program text into bits
which  can  be run; lint concentrates on issues of portabil-
ity, style, and efficiency. Lint can  afford  to  be  wrong,
since  incorrectness and over-conservatism are merely annoy-
ing, not fatal. The compiler can be fast since it knows that
lint will cover its flanks. Finally, the programmer can con-
centrate at one stage of the programming process  solely  on
the algorithms, data structures, and correctness of the pro-
gram, and then later retrofit, with the  aid  of  lint,  the
desirable properties of universality and portability.

References

1.   B. W. Kernighan and D. M. Ritchie,  The  C  Programming
     Language,  Prentice-Hall, Englewood Cliffs, New Jersey,
     1978.

2.   S. C. Johnson, "Yacc -  Yet Another Compiler-Compiler,"
     Comp. Sci. Tech. Rep. No. 32, Bell Laboratories, Murray
     Hill, New Jersey, July 1975.

3.   M. E. Lesk, "Lex - A Lexical Analyzer Generator," Comp.
     Sci. Tech. Rep. No. 39, Bell Laboratories, Murray Hill,
     New Jersey, October 1975.

4.   S. C. Johnson and D.  M.  Ritchie,  "UNIX  Time-Sharing
     System: Portability of C Programs and the UNIX System,"
     Bell Sys. Tech. J., vol.  57,  no.  6,  pp.  2021-2048,
     1978.

PS1:9-16                           Lint, a C Program Checker

5.   S. C. Johnson, "A Portable Compiler: Theory  and  Prac-
     tice," Proc. 5th ACM Symp. on Principles of Programming
     Languages, pp. 97-104, January 1978.

Lint, a C Program Checker                           PS1:9-17

Appendix:   Current Lint Options

     The command currently has the form

        lint [-options ] files... library-descriptors...

The options are

h    Perform heuristic checks

p    Perform portability checks

v    Don't report unused arguments

u    Don't report unused or undefined externals

b    Report unreachable break statements.

x    Report unused external declarations

a    Report assignments of long to int or shorter.

c    Complain about questionable casts

n    No library checking is done

s    Same as h (for historical reasons)

Generated on 2014-04-02 20:57:59 by $MirOS: src/scripts/roff2htm,v 1.79 2014/02/10 00:36:11 tg Exp $

These manual pages and other documentation are copyrighted by their respective writers; their source is available at our CVSweb, AnonCVS, and other mirrors. The rest is Copyright © 2002‒2014 The MirOS Project, Germany.
This product includes material provided by Thorsten Glaser.

This manual page’s HTML representation is supposed to be valid XHTML/1.1; if not, please send a bug report – diffs preferred.