Using lint [ HP C Programmer's Guide ] MPE/iX 5.0 Documentation
HP C Programmer's Guide
Using lint
The main purpose of lint is to supply the programmer with warning
messages about problems with the source code's style, efficiency,
portability, and consistency. The lint command can be used before
compiling a program to check for syntax errors and after compiling a
program to test for subtle errors such as type differences.
Error messages and lint warnings are sent to standard error (stderr).
Once the code errors are corrected, the C source file(s) should be run
through the C compiler to produce the necessary object code.
The lint command has the form:
lint [options]files ... library-descriptors ...
where options are options flags to control lint checking and messages,
files are the files to be checked that end with .c or .ln, and library
descriptors are the names of libraries to be used in checking the
program.
The options that are currently supported by the lint command are:
-a Suppresses messages about assignments of long
values to variables that are not long.
-b Suppresses messages about break statements that
cannot be reached.
-c Only checks for intrafile bugs; leaves external
information in files suffixed with .ln.
-h Does not apply heuristics (which attempt to
detect bugs, improve style, and reduce waste).
-n Does not check for compatibility with either
the standard or the portable lint library.
-o name Creates a lint library from input files named
llib-lname.ln.
-p Attempts to check portability to other dialects
of C language.
-s Checks for cases where the alignment of
structures, unions, and pointers may not be
portable.
-u Suppresses messages about function and external
variables used and not defined or defined and
not used.
-v Suppresses messages about unused arguments and
functions.
-x Does not report variables referred to by
external declarations but never used.
-Aa Invokes lint in ANSI mode.
-Ac Invokes lint in compatibility mode. The
default is compatibility mode.
The names of files that contain C language programs should end with the
suffix .c, which is mandatory for lint and the C compiler.
The lint command accepts certain arguments, such as:
-lm
The lint library files are processed almost exactly like ordinary source
files. The only difference is that functions that are defined on a
library file but are not used on a source file do not result in messages.
The lint command does not simulate a full library search algorithm and
will print messages if the source files contain a redefinition of a
library routine.
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 language program is run. When the -p option is
used, another file is checked containing descriptions of the standard
library routines which are expected to be portable across various
machines. The -n option can be used to suppress all library checking.
Directives
The alternative to using options to suppress lint's comments about
problem areas is to use directives. Directives appear in the source code
in the form of code comments. The lint command recognizes five
directives.
/*NOTREACHED*/ Stops an unreachable code comment about the
next line of code.
/*NOSTRICT*/ Stops lint from strictly type checking the next
expression.
/*ARGSUSED*/ Stops a comment about any unused parameters for
the following function.
/*VARARGSn*/ Stops lint from reporting variable numbers of
parameters in calls to a function. The
function's definition follows this comment.
The first n parameters must be present in each
call to the function; lint comments if they
aren't. If /*VARARGS*/ appears without the n,
none of the parameters must be present. This
comment must precede the actual code for a
function. It should not precede extern
declarations.
/*LINTLIBRARY*/ Tells lint that the source file is used to
create a lint library file and to suppress
comments about the unused functions. lint
objects if other files redefine routines that
are found there. This directive must be placed
at the beginning of a source file.
Problem Detection
Remember that a compiler reports errors only when it encounters program
source code that cannot be converted into object code. The main purpose
of lint is to find problem areas in C source code that it considers to be
inefficient, nonportable, bad style, or a possible bug, but which the C
compiler accepts as error-free because it can be converted into object
code.
Comments about problems that are local to a function are produced as each
problem is detected. They have the following form:
(line #) warning: message text
Information about external functions and variables is collected and
analyzed after lint has processed the source files. At that time, if a
problem has been detected, it outputs a warning message with the form
message text
followed by a list of external names causing the message and the file
where the problem occurred.
Code causing lint to issue a warning message should be analyzed to
determine the source of the problem. Sometimes the programmer has a
valid reason for writing the problem code. Usually, though, this is not
the case. The lint command can be very helpful in uncovering subtle
programming errors.
The lint command checks the source code for certain conditions, about
which it issues warning messages. These can be grouped into the
following categories:
* variable or function is declared but not used
* variable is used before it is set
* portion of code is unreachable
* function values are used incorrectly
* type matching does not adhere strictly to C rules
* code has portability problems
* code construction is strange
The code that you write may have constructions in it that lint objects to
but that are necessary to its application. Warning messages about
problem areas that you know about and do not plan to correct can be
suppressed. There are two methods for suppressing warning messages from
lint. The use of lint options is one. The lint command can be called
with any combination of its defined option set. Each option causes lint
to ignore a different problem area. The other method is to insert lint
directives into the source code. For information about lint directives,
see the section "Directives" in this chapter.
Unused Variables and Functions.
The lint command objects if source code declares a variable that is never
used or defines a function that is never called. Unused variables and
functions are considered bad style because their declarations clutter the
code.
Unused static identifiers cause the following message:
(1)static identifier 'name' defined but never used
Unused automatic variables cause the following message:
(1) warning: 'name' unused in function 'name'
A function or external variable that is unused causes the message
name defined but never used
followed by the function or variable name, the line number and file in
which it was defined. The lint command also looks at the special case
where one of the parameters of a function is not used. The warning
message is:
warning: (line number) 'arg_name' in func_name'
If functions or external variables are declared but never used or
defined, lint responds with
name declared but never used or defined
followed by a list of variable and functions names and the names of files
where they were declared.
Suppressing Unused Functions and Variables Reports.
Sometimes it is necessary to have unused function parameters to support
consistent interfaces between functions. The -v option can be used with
lint to suppress warnings about unused parameters.
If lint is run on a file that is linked with other files at compile time,
many external variables and functions can be defined but not used, as
well as used but not defined. If there is no guarantee that the
definition of an external object is always seen before the object code is
used, it is declared extern. The -u option can be used to stop
complaints about all external objects, whether or not they are declared
extern. If you want to inhibit complaints about only the extern declared
functions and variables, use the -x option.
Set/Used Information.
A problem exists in a program if a variable's value is used before it is
assigned. Although lint attempts to detect occurrences of this, it takes
into account only the physical location of the code. If code using a
local variable is located before the variable is given a value, the
message is:
warning: 'name' may be used before set
The lint command also objects if automatic variables are set in a
function but not used. The message given is:
warning: 'name' set but not used in function 'func_name'
Note that lint does not have an option for suppressing the display of
warnings for variables that are used but not set or set but not used.
Unreachable Code.
The lint command checks for three types of unreachable code. Any
statement following a goto, break, continue, or return statement must
either be labeled or reside in an outer block for lint to consider it
reachable. If neither is the case, lint responds with:
warning: (line number) statement not reached
The same message is given if lint finds an infinite loop. It only checks
for the infinite loop cases of while(1) and for(;;). The third item that
lint looks for is a loop that cannot be entered from the top. If one is
found, then the message sent is:
warning: loop not entered from top
The lint command's detection of unreachable code is by no means
exhaustive. Warning messages can be issued about valid code, and
conversely lint may overlook code that cannot be reached.
Programs that are generated by yacc or lex can have many unreachable
break statements. Normally, each one causes a complaint from lint. The
-b option can be used to force lint to ignore unreachable break
statements.
Function Value.
The C compiler allows a function containing both the statement
return();
and the statement
return(expression);
to pass through without complaint. The lint command, however, detects
this inconsistency and responds with the message:
warning: function 'name' has 'return(expression)' 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 is a tests false, f will call g and then return with no
defined value. This will trigger a message for 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.
On a global scale, lint detects cases where a function returns a value
that is sometimes or never used. When the value is never used, it may
constitute an inefficiency in the function definition. When the value is
sometimes used, it may represent bad style (e.g., not testing for error
conditions).
The lint command will not issue a diagnostic message if that function
call is cast as void. For example,
(void) printf("%d\n",i);
tells lint to not warn about the ignored return value.
The dual problem--using a function value when the function does not
return one--is also detected. This is a serious problem.
The lint command does not have an option for suppressing the display of
warning for inconsistent return functions and functions that return no
value.
Portability.
The -p option of lint aids the programmer is writing portable code in
four areas:
* character comparisons
* pointer alignments (this is default on PA-RISC computers)
* length of external variables
* type casting
Character representation varies on different machines. Characters may be
implemented as signed values. As a result, certain comparisons with
characters give different results on different machines. The expression
c<0
where c is defined as type char, is always false if characters are
unsigned values. If, however, characters are signed values, the
expression could be either true or false. Where character comparisons
could result in different values depending on the machine used, lint
outputs the message:
warning: nonportable character comparison
Legal pointer assignments are determined by the alignment restrictions of
the particular machine used. For example, one machine may allow
double-precision values to begin on any modulo-4 boundary, but another
may restrict them to modulo-8 boundaries. If alignment requirements are
different, code containing an assignment of a double pointer to an
integer pointer could cause problems. The lint command attempts to
detect where the effect of pointer assignments is machine dependent. The
warning that it outputs is:
warning: possible pointer alignment problem
The amount of information about external symbols that is loaded depends
on: the machine being used, the number of significant characters, and
whether or not uppercase/lowercase distinction is kept. The lint -p
command truncates all external symbols to six characters and allows only
one case distinction. (It changes uppercase characters to lowercase.)
This provides a worst-case analysis so that the uniqueness of an external
symbol is not machine-dependent.
The effectiveness of type casting in C programs can depend on the machine
that is used. For this reason, lint ignores type casting code. All
assignments that use it are subject to lint's type checking.
Alignment Portability.
The -s option of the lint command checks for the following portability
considerations:
* pointer alignments (same as -p option)
* a structure's member alignments
* trailing padding of structures and unions
The checks made for pointer alignments are exactly the same as for the -p
option. The warning for these cases is:
warning: possible pointer alignment problem
The alignment of structure members is different between architectures.
For example, MC680x0 computers pad structures internally so that all
fields of type int begin on an even boundary. In contrast, PA-RISC
computers pad structures so that all fields of type int begin on a
four-byte boundary. The following structure will be aligned differently
on the two architectures:
struct s
{ char c;
long l; /* The offset equals 2 on MC680x0 computers */
}; /* and 4 on PA-RISC computers. */
In many cases the different alignment of structures does not affect the
behavior of a program. However, problems can happen when raw structures
are written to a file on one architecture and read back in on another.
The lint command checks for cases where a structure member is aligned on
a boundary that is not a multiple of its size (for example, int on int
boundary, short on short boundary, and double on double boundary). The
warning that it outputs is:
warning: alignment of struct 'name' may not be portable
The lint command also checks for cases where the internal padding added
at the end of a structure may differ between architectures. The amount
of trailing padding can change the size of a structure. The warning that
lint outputs is:
warning: trailing padding of struct/union 's' may not be portable
Strange Constructions.
A strange construction is code that lint considers to be bad style or a
possible bug.
The lint command looks for code that has no effect. For example,
*p++;
where the * has no effect. The statement is equivalent to "p++;". In
cases like this, the message
warning: null effect
is sent.
The treatment of unsigned numbers as signed numbers in comparison causes
lint to report the following:
warning: degenerate unsigned comparison
The following code would produce such a message:
unsigned x;
.
.
.
if (x >=0) ...
The lint command also objects if constants are treated as variables. If
the boolean expression in a conditional has a set value due to constants,
such as
if(1 !=0) ...
lint's response is:
warning: constant in conditional context
To avoid operator precedence confusion, lint encourages using parentheses
in expressions by sending the message:
warning: precedence confusion possible: parenthesize!
The lint command judges it bad style to redefine an outer block variable
in an inner block. Variables with different meanings should normally
have different names. If variables are redefined, the message sent is:
warning: name redefinition hides earlier one
The -h option suppresses lint diagnostics of strange constructions.
Standards Compliance.
The lint libraries are arranged for standards checking. For example,
lint -D_POSIX_SOURCE file.c
checks for routines referenced in file.c but not specified in the POSIX
standard.
The lint command also accepts ANSI standard C -Aa as well as compatible C
-Ac. In ANSI mode, lint invokes the ANSI preprocessor (/lib/cpp.ansi)
instead of the compatibility preprocessor (/lib/cpp). ANSI mode lint
should be used on source that is compiled with the ANSI standard C
compiler.
MPE/iX 5.0 Documentation