You can use the
lint
program to check your C programs
for potential coding problems.
The
lint
program checks
a program more carefully than some C compilers, and displays messages that
point out possible problems.
Some of the messages require corrections to the
source code; others are only informational messages and do not require corrections.
This chapter addresses the following topics:
Syntax of the
lint
command (Section 6.1)
Program flow checking (Section 6.2)
Data type checking (Section 6.3)
Variable and function checking (Section 6.4)
Checking the use of variables before they are initialized (Section 6.5)
Migration checking (Section 6.6)
Portability checking (Section 6.7)
Checking for coding errors and coding style differences (Section 6.8)
Increasing table sizes for large programs (Section 6.9)
Creating a
lint
library (Section 6.10)
Understanding
lint
error messages (Section 6.11)
Using warning class options to suppress
lint
messages (Section 6.12)
Generating function prototypes for compile-time detection of syntax errors (Section 6.13)
See
lint
(1)lint
options.
6.1 Syntax of the lint Command
The
lint
command has the
following syntax:
lint
[ options ] [ file ... ]
Options to
control
lint
checking operations.
The
cc
driver options,
-std
,
-std0
, and
-std1
, are available as
options to
lint
.
These options affect the parsing of the
source as well as the selection of the
lint
library to
use.
Selecting either the
-std
or
-std1
options turns on ANSI parsing rules in
lint
.
When you use the
-MA
lint
option,
-std1
is used for the C preprocessing phase
and
_ANSI_C_SOURCES
is defined using the
-D
preprocessor option.
The following table describes the action
lint
takes for each option:
lint Option | Preprocessor Switch | lint Parsing | lint Library |
-MA |
-std1
and
-D_ANSI_C_SOURCE |
ANSI | llib-lansi.ln |
-std |
-std |
ANSI | llib-lcstd.ln |
-std1 |
-std1 |
ANSI | llib-lcstd.ln |
-std0 |
-std0 |
EXTD [Footnote 5] |
llib-lc.ln |
The name of the
C language source file for
lint
to check.
The name must
have one of the following suffixes:
Suffix | Description |
.c |
C source file |
.i |
File produced by the C preprocessor (cpp ) |
.ln |
lint
library file |
Note that
lint
library files are the result of
a previous invocation of the
lint
program with either the
-c
or
-o
option.
They are analogous to the
.o
files produced by the
cc
command when it is
given a
.c
file as input.
The ability to specify
lint
libraries as input to the
lint
program facilitates
intermodule interface checking in large applications.
Adding rules that specify
the construction of
lint
libraries to their makefiles can
make building such applications more efficient.
See
Section 6.10
for a discussion on how to create a
lint
library.
You can also specify as input a
lint
library that
resides in one of the system's default library search directories by using
the
-lx
option.
The library
name must have the following form:
llib-llibname.ln
By default, the
lint
program appends the extended
C (K&R C)
lint
library (llib-lc.ln
)
to the list of files specified on the command line.
If the
-std
or
-std1
option is used, it appends the
standard C
lint
library (llib-lcstd.ln
)
instead.
The following additional libraries are included with the system:
Library | Description | Specify As |
crses |
Checks curses library call syntax | -lcrses |
m |
Checks math library call syntax | -lm |
port |
Checks for portability with other systems | -p
(not
-lport ) |
ansi |
Enforces ANSI C standard rules | -MA
(not
-lansi ) |
If you specify no options on the command line, the
lint
program checks the specified C source files and writes messages about any
of the following coding problems that it finds:
Loops that are not entered and exited normally
Data types that are not used correctly
Functions that are not used correctly
Variables that are not used correctly
Coding techniques that could cause problems if a program is moved to another system
Nonstandard coding practices and style differences that could cause problems
The
lint
program also checks for syntax errors in
statements in the source programs.
Syntax checking is always done and is not
influenced by any options that you specify on the
lint
command.
If
lint
does not report any errors, the program has
correct syntax and will compile without errors.
Passing that test, however,
does not mean that the program will operate correctly or that the logic design
of the program is accurate.
See
Section 6.10
for information on how to create
your own
lint
library.
6.2 Program Flow Checking
The
lint
program checks for dead code, that
is, parts of a program that are never executed because they cannot be reached.
It writes messages about statements that do not have a label but immediately
follow statements that change the program flow, such as
goto
,
break
,
continue
, and
return
.
The
lint
program also detects and writes messages
for loops that cannot be entered at the top.
Some programs that include this
type of loop may produce correct results; however, this type of loop can cause
problems.
The
lint
program does not recognize functions that
are called but can never return to the calling program.
For example, a call
to
exit
may result in code that cannot be reached, but
lint
does not detect it.
Programs generated by
yacc
and
lex
may have hundreds of
break
statements that cannot be reached.
The
lint
program normally
writes an error message for each of these
break
statements.
To eliminate the extraneous code associated with these
break
statements, use the
-O
option to the
cc
command when compiling the program.
Use the
-b
option
with the
lint
program to prevent it from writing these
messages when checking
yacc
and
lex
output code.
(For information on
yacc
and
lex
, see the
Programming Support Tools
manual.)
6.3 Data Type Checking
The
lint
program enforces
the type-checking rules of the C language more strictly than the compiler
does.
In addition to the checks that the compiler makes,
lint
checks for potential data type errors in the following areas:
Binary operators and implied assignments
Structures and unions
Function definition and uses
Enumerators
Type-checking control
Type casts
Details on each of these potential problem areas are provided in the
sections that follow.
6.3.1 Binary Operators and Implied Assignments
The C language allows the following data types to be mixed in statements, and the compiler does not indicate an error when they are mixed:
char
short
int
long
unsigned
float
double
The C language automatically converts data types within this group to provide the programmer with more flexibility in programming. This flexibility, however, means that the programmer, not the language, must ensure that the data type mixing produces the desired result.
You can mix these data types when using them in the following ways (in
the examples,
alpha
is type
char
and
num
is type
int
):
Operands on both sides of an assignment operator, for example:
alpha = num; /* alpha converts to int */
Operands in a conditional expression, for example:
value=(alpha < num) ? alpha : num; /* alpha converts to int */
Operands on both sides of a relational operator, for example:
if( alpha != num ) /* alpha converts to int */
The type of an argument in a
return
statement
is converted to the type of the value that the function returns, for example:
funct(x) /* returns an integer */ { return( alpha ); }
The data types of pointers must agree exactly, except that you can mix
arrays of any type with pointers to the same type.
6.3.2 Structures and Unions
The
lint
program checks structure operations for the following requirements:
The left operand of the structure pointer operator (->
) must be a pointer to a structure.
The left operand of the structure member operator (.
) must be a structure.
The right operand of these operators must be a member of the same structure.
The
lint
program makes similar checks for references
to unions.
6.3.3 Function Definition and Uses
The
lint
program
applies strict rules to function argument and return value matching.
Arguments
and return values must agree in type, with the following exceptions:
You can match arguments of type
float
with
arguments of type
double
.
You can match arguments within the following types:
char
short
int
unsigned
You can match pointers with the associated arrays.
The
lint
program checks enumerated data type variables to ensure that
they meet the following requirements:
Enumerator variables or members of an enumerated type are not mixed with other types or other enumerator variables.
The enumerated data type variables are only used in the following areas:
Type casts in the C language allow the program
to treat data of one type as if it were data of another type.
The
lint
program can check for type casts and write a message if it
finds one.
The
-wp
and
-h
options for the
lint
command line control the writing of warning messages about
casts.
If neither of these options are used,
lint
produces
warning messages about casts that may cause portability problems.
In migration checking mode,
-Qc
suppresses cast
warning messages (see
Section 6.6).
6.4 Variable and Function Checking
The
lint
program checks for variables
and functions that are declared in a program but not used.
The
lint
program checks for the following errors in the use of variables
and functions:
Functions that return values inconsistently
Functions that are defined but not used
Arguments to a function call that are not used
Functions that can return either with or without values
Functions that return values that are never used
Programs that use the value of a function when the function does not return a value
Details on each of these potential problem areas are provided
in the sections that follow.
6.4.1 Inconsistent Function Return
If a function returns a value under one set of conditions but not under
another, you cannot predict the results of the program.
The
lint
program checks functions for this type of behavior.
For example,
if both of the following statements are in a function definition, a program
calling the function may or may not receive a return value:
return(expr);
.
.
.
return;
These statements cause the
lint
program
to write the following message to point out the potential problem:
function name has return(e); and return
The
lint
program also checks functions for returns that are caused by reaching
the end of the function code (an implied return).
For example, in the following
part of a function, if
a
tests false,
checkout
calls
fix_it
and then returns with no defined
return value:
checkout (a) { if (a) return (3); fix_it (); }
These statements cause the
lint
program to write
the following message:
function checkout has return(e); and return
If
fix_it
, like
exit
, never returns,
lint
still writes the message even though nothing is wrong.
6.4.2 Function Values That Are Not Used
The
lint
program checks for cases in which a function
returns a value and the calling program may not use the value.
If the value
is never used, the function definition may be inefficient and should be examined
to determine whether it should be modified or eliminated.
If the value is
sometimes used, the function may be returning an error code that the calling
program does not check.
6.4.3 Disabling Function-Related Checking
To prevent
lint
from checking for problems with functions,
specify one or more of the following options to the
lint
command:
-x |
Do not check for variables that are declared
in an
extern
statement but never used. |
-v |
Do not check for arguments to functions that are not used, except for those that are also declared as register arguments. |
-u |
Do not check for functions and external variables
that are either used and not defined or defined and not used.
Use this option
to eliminate useless messages when you are running
lint
on a subset of files of a larger program.
(When using
lint
with some, but not all, files that operate together, many of the functions
and variables defined in those files may not be used.
Also, many functions
and variables defined elsewhere may be used.) |
You can also place directives in the program to control checking:
To prevent
lint
from warning about unused
function arguments, add the following directive to the program before the
function definition:
/*ARGSUSED*/
To prevent
lint
from writing messages about
variable numbers of arguments in calls to a function, add the following directive
before the function definition:
/*VARARGS
To check the first several arguments and leave the later arguments unchecked,
add a digit (n) to the end of the
VARARGS
directive to give the number of arguments that should be checked,
such as:
/*VARARGS2*/
When
lint
reads this directive, it checks only the
first two arguments.
To suppress complaints about unused functions and function arguments in an entire file, place the following directive at the beginning of the file:
/*LINTLIBRARY*/
This is equivalent to using the
-v
and
-x
options.
To permit a standard prototype checking library to be formed from header files by making function prototype declarations appear as function definitions, use the following directive:
/*LINTSTDLIB
[
_filename
]*/
The
/*LINTSTDLIB*/
directive implicitly activates
the functions of the
/*NOTUSED*/
and
/*LINTLIBRARY*/
directives to reduce warning noise levels.
When a file is referenced
(filename), only prototypes in that file are expanded.
Multiple
/*LINTSTDLIB_filename
*/
statements are allowed.
(See
Section 6.10.1
for more details on the use of
/*LINTSTDLIB*/
directives.)
To suppress warnings about all used but undefined external symbols and functions that are subsequently encountered in the file, use the following directive:
/*NOTDEFINED*/
To suppress comments about unreachable code, use the following directive:
/*NOTREACHED*/
When placed at appropriate points in a program (typically immediately
following a
return
,
break
, or
continue
statement), the
/*NOTREACHED*/
directive
stops comments about unreachable code.
Note that
lint
does
not recognize the
exit
function and other functions that
may not return.
To suppress warnings about all unused external symbols, functions, and function parameters that are subsequently encountered in the file, use the following directive:
/*NOTUSED*/
The
/*NOTUSED*/
directive is similar to the
/*LINTLIBRARY*/
directive, although
/*NOTUSED*/
also applies to external symbols.
6.5 Checking on the Use of Variables Before They Are Initialized
The
lint
program checks for the use of a local variable (auto
and
register
storage classes) before a value has been assigned to it.
Using a variable with an
auto
(automatic) or
register
storage class also includes taking the address of the variable.
This is necessary because the program can use the variable (through its address)
any time after it knows the address of the variable.
Therefore, if the program
does not assign a value to the variable before it finds the address of the
variable,
lint
reports an error.
Because
lint
only checks the physical order of the
variables and their usage in the file, it may write messages about variables
that are initialized properly (in execution sequence).
The
lint
program
recognizes
and writes messages about:
Initialized automatic variables
Variables that are used in the expression that first sets them
Variables that are set and never used
Note
The Tru64 UNIX operating system initializes
static
andextern
variables to zero. Therefore,lint
assumes that these variables are set to zero at the start of the program and does not check to see if they have been assigned a value when they are used. When developing a program for a system that does not do this initialization, ensure that the program setsstatic
andextern
variables to an initial value.
Use
lint
to check
for all common programming techniques that might cause problems when migrating
programs from 32-bit operating systems to the Tru64 UNIX operating system.
The
-Q
option provides support for checking ULTRIX
and DEC OSF/1 Version 1.0 programs that you are migrating to 64-bit systems.
Because the
-Q
option disables checking for
most other programming problems, use this option only for migration checking.
Suboptions are available to suppress specific categories of checking.
For
example, entering
-Qa
suppresses the checking of
pointer alignment problems.
You can enter more than one suboption with the
-Q
option, for example,
-QacP
to
suppress checking for pointer alignment problems, problematic type casts,
and function prototype checks, respectively.
For more information about migration
checking, see
lint
(1)6.7 Portability Checking
Use
lint
to
help ensure that you can compile and run C programs using different C language
compilers and other systems.
The following sections indicate areas to check before compiling the program on another system. Checking only these areas, however, does not guarantee that the program will run on any system.
Note
The
llib-port.ln
library is brought in by using the-p
option, not by using the-lport
option.
Some systems define characters
in a C language program as signed quantities with a range from -128
to 127; other systems define characters as positive values.
The
lint
program checks for character comparisons or assignments that
may not be portable to other systems.
For example, the following fragment
may work on one system but fail on systems where characters always take on
positive values:
char c;
.
.
.
if( ( c = getchar() ) <0 )...
This statement causes the
lint
program to write the following message:
nonportable character comparison
To make the program work on systems
that use positive values for characters, declare
c
as an
integer because
getchar
returns integer values.
6.7.2 Bit Field Uses
Bit fields
may produce problems when a program is transferred to another system.
Bit
fields may be signed quantities on the new system.
Therefore, when constant
values are assigned to a bit field, the field may be too small to hold the
value.
To make this assignment work on all systems, declare the bit field
to be of type
unsigned
before assigning values to it.
6.7.3 External Name Size
When changing from one type of system to another, be aware of differences in the information retained about external names during the loading process:
The number of characters allowed for external names can vary.
Some programs that the compiler command calls and some of the functions that your programs call can further limit the number of significant characters in identifiers. (In addition, the compiler adds a leading underscore to all names and keeps uppercase and lowercase characters separate.)
On some systems, uppercase or lowercase may not be important or may not be allowed.
When transferring from one system to another, you should always take the following steps to avoid problems with loading a program:
Review the requirements of each system.
Run
lint
with the
-p
option.
The
-p
option tells
lint
to change
all external symbols to lowercase and limit them to six characters while checking
the input files.
The messages produced identify the terms that may need to
be changed.
6.7.4 Multiple Uses and Side Effects
Be careful when using complicated expressions because of the following considerations:
The order in which complex expressions are evaluated differs in many C compilers.
Function calls that are arguments of other functions may not be treated the same as ordinary arguments.
Operators such as assignment, increment, and decrement may cause problems when used on different systems.
The following situations demonstrate the types of problems that can result from these differences:
If any variable is changed by a side effect of one of the operators and is also used elsewhere in the same expression, the result is undefined.
The evaluation of the variable
years
in
the following
printf
statement is confusing because on
some machines
years
is incremented before the function
call and on other machines it is incremented after the function call:
printf( "%d %d\n", ++years, amort( interest, years ) );
The
lint
program checks for simple scalar
variables that may be affected by evaluation order problems, such as in the
following statement:
a[i]=b[i++];
This statement
causes the
lint
program to write the following message:
warning: i evaluation order undefined
6.8 Checking for Coding Errors and Coding Style Differences
Use
lint
to
detect possible coding errors, and to detect differences from the coding style
that
lint
expects.
Although coding style is mainly a matter
of individual taste, examine each difference to ensure that the difference
is both needed and accurate.
The following sections indicate the types of
coding and style problems that
lint
can find.
6.8.1 Assignments of Long Variables to Integer Variables
If you assign variables of type
long
to variables
of type
int
, the program may not work properly.
The
long
variable is truncated to fit in the integer space and data
may be lost.
An error of this type frequently occurs when a program that uses more
than one
typedef
is converted to run on a different system.
To prevent
lint
from writing messages when it detects
assignments of
long
variables to
int
variables, use the
-a
option.
6.8.2 Operator Precedence
The
lint
program detects possible or potential errors
in operator precedence.
Without parentheses to show order in complex sequences,
these errors can be hard to find.
For example, the following statements are
not clear:
if(x&077==0). . . /* evaluated as: if(x & (077 == 0) ) */ /* should be: if( (x & 077) == 0) */ x<<2+40 /* evaluated as: x <<(2+40) */ /* should be: (x<<2) + 40 */ /* shift x left 42 positions */
Use parentheses
to make the operation more clearly understood.
If you do not,
lint
issues a message.
6.8.3 Conflicting Declarations
The
lint
program writes messages about variables
that are declared in inner blocks in ways that conflict with their use in
outer blocks.
This practice is allowed, but may cause problems in the program.
Use the
-h
option with the
lint
program to prevent
lint
from checking for conflicting declarations.
6.9 Increasing Table Size
The
lint
command provides the
-N
option and related suboptions to allow you to increase the size
of various internal tables at run time if the default values are not enough
for your program.
These tables include:
Symbol table
Dimension table
Local type table
Parse tree
These tables are dynamically allocated by the
lint
program.
Using the
-N
option on large source files
can improve performance.
6.10 Creating a lint Library
For programming projects that define additional library
routines, you can create an additional
lint
library to
check the syntax of the programs.
Using this library, the
lint
program can check the new functions in addition to the standard C language
functions.
To create a new
lint
library, follow these steps:
Create an input file that defines the new functions.
Process the input file to create the
lint
library file.
Run
lint
using the new library.
The following sections describe these steps.
6.10.1 Creating the Input File
The following example shows an input file that defines three additional
functions for
lint
to check:
/*LINTLIBRARY*/ #include <dms.h> int dmsadd( rmsdes, recbuf, reclen ) int rmsdes; char *recbuf; unsigned reclen; { return 0; } int dmsclos( rmsdes) int rmsdes; { return 0; } int dmscrea( path, mode, recfm, reclen ) char *path; int mode; int recfm; unsigned reclen; { return 0; }
The input file is a text file that you create with an editor. It consists of:
A directive to tell the
cpp
program that
the following information is to be made into a library of
lint
definitions:
/*LINTLIBRARY*/
A series of function definitions that define:
The type of the function (int
in the example)
The name of the function
The parameters that the function expects
The types of the parameters
The value that the function returns
Alternatively, you can create a
lint
library file
from function prototypes.
For example, assume that the
dms.h
file includes the following prototypes:
int dmsadd(int, char*, unsigned); int dmsclose(int); int dmscrea(char*, int, int, unsigned);
In this case, the input file contains the following:
/*LINTSTDLIB*/ #include <dms.h>
In the case where a header file may include other headers, the
LINTSTDLIB
command can be restricted to specific files:
/*LINTSTDLIB_dms.h*/
In this case, only prototypes declared in
dms.h
will
be expanded.
Multiple
LINTSTDLIB
commands can be included.
In all cases, the name of the input file must have the prefix
llib-l
.
For example, the name of the sample input file created in
this section could be
llib-ldms
.
When choosing the name
of the file, ensure that it is not the same as any of the existing files in
the
/usr/ccs/lib
directory.
6.10.2 Creating the lint Library File
The following command creates a
lint
library file
from the input file described in the previous section:
% lint [options] -c llib_ldms.c
This command tells
lint
to create a
lint
library file,
llib-ldms.ln
, using the file
llib-ldms.c
as input.
To use
llib-ldms.ln
as
a system
lint
library (that is, a library specified in
the
-lx
option of the
lint
command), move it to
/usr/ccs/lib
.
Use the
-std
or
-std1
option to use ANSI
preprocessing rules to build the library.
6.10.3 Checking a Program with a New Library
To check a program using a new library, use the
lint
command with the following format:
lint -lpgm filename.c
The variable
pgm
represents the identifier
for the library, and the variable
filename.c
represents
the name of the file containing the C language source code that is to be checked.
If no other options are specified, the
lint
program checks
the C language source code against the standard
lint
library
in addition to checking it against the indicated special
lint
library.
6.11 Understanding lint Error Messages
Although most error messages produced by
lint
are self-explanatory, certain messages may be misleading without additional
explanation.
Usually, once you understand what a message means, correcting
the error is straightforward.
The following is a list of the more ambiguous
lint
messages:
constant argument to NOT
A constant is used with the NOT operator (!). This is a common coding practice and the message does not usually indicate a problem. The following program demonstrates the type of code that can generate this message:
% cat x.c #include <stdio.h> #define SUCCESS 0 main() { int value = !SUCCESS; printf("value = %d\n", value); return 0; } % lint -u x.c "x.c", line 7: warning: constant argument to NOT % ./x value = 1 %
The program runs as expected,
even though
lint
complains.
Recommended Action:
Suppress these
lint
warning messages by using the
-wC
option.
constant in conditional context
A constant is used where a conditional is expected. This problem occurs often in source code due to the way in which macros are encoded. For example:
typedef struct _dummy_q { int lock; struct _dummy_q *head, *tail; } DUMMY_Q; #define QWAIT 1 #define QNOWAIT 0 #define DEQUEUE(q, elt, wait) [1] \ for (;;) { simple_lock(&(q)->lock); if (queue_empty(&(q)->head)) if (wait) { [1] \ assert(q); simple_unlock(&(q)->lock); continue; } else *(elt) = 0; else dequeue_head(&(q)->head); simple_unlock(&(q)->lock); break; } int doit(DUMMY_Q *q, int *elt) { DEQUEUE(q, elt, QNOWAIT); }
The
QWAIT
or
QNOWAIT
option is passed as the third argument (wait
)
and is later used in the
if
statement.
The code is correct,
but
lint
issues the warning because constants used in this
way are normally unnecessary and often generate wasteful or unnecessary instructions.
[Return to example]
lint
warning messages by using the
-wC
option.
conversion from long may lose accuracy
A signed
long
is copied to a smaller entity (for
example, an
int
).
This message is not necessarily misleading;
however, if it occurs frequently, it may or may not indicate a coding problem,
as shown in the following example:
long BuffLim = 512; [1] void foo (buffer, size) char *buffer; int size; { register int count; register int limit = size < (int)BufLimit ? size : (int)BufLim; [1]
The
lint
program reports
the conversion error, even though the appropriate
(int)
cast exists.
[Return to example]
lint
reports this message, or suppress
the message by using the
-wl
option.
declaration is missing declarator
A line in the declaration section of the program contains just a semicolon (;). Although you would not deliberately write code like this, it is easy to inadvertently generate such code by using a macro followed by a semicolon. If, due to conditionalization, the macro is defined as empty, this message can result.
Recommended Action: Remove the trailing semicolon.
degenerate unsigned comparison
An unsigned comparison is being performed against a signed value when the result is expected to be less than zero. The following program demonstrates this situation:
% cat x.c #include <stdio.h> unsigned long offset = -1; main() { if (offset < 0) { [1] puts ("code is Ok..."); return 0; } else { puts ("unsigned comparison failed..."); return 1; } } % cc -g -o x x.c % lint x.c "x.c" line 7: warning: degenerate unsigned comparison % ./x unsigned comparison failed... %
Unsigned comparisons such as this will fail if the unsigned variable contains a negative value. The resulting code may be correct, depending upon whether the programmer intended a signed comparison. [Return to example]
Add a
(long)
cast before
offset
in the
if
comparison.
Change the declaration of
offset
from
unsigned
to
long
.
In certain cases, it might be necessary to cast the signed value to unsigned.
function prototype not in scope
This error is not strictly related to function prototypes, as the message implies. Actually, this error occurs from invoking any function that has not been previously declared or defined.
Recommended Action: Add the function prototype declaration.
null effect
The
lint
program detected a cast or statement that does nothing.
The following
code segments demonstrate various coding practices that cause
lint
to generate this message:
scsi_slot = device->ctlr_hd->slot,unit_str; [1] #define MCLUNREF(p) \ (MCLMAPPED(p) && --mclrefcnt[mtocl(p)] == 0) (void) MCLUNREF(m); [2]
Reason:
unit_str
does nothing.
[Return to example]
Reason:
(void)
is unnecessary;
MCLUNREF
is a macro.
[Return to example]
possible pointer alignment problem
A pointer is used in a way that may cause an alignment problem.
The
following code segment demonstrates the type of code that causes
lint
to generate this message:
read(p, args, retval) struct proc *p; void *args; long *retval; { register struct args { long fdes; char *cbuf; unsigned long count; } *uap = (struct args *) args; [1] struct uio auio; struct iovec aiov;
The line
*uap
causes the error to be reported.
Because this construct is valid
and occurs throughout the kernel source, this message is filtered out.
[Return to example]
precision lost in field assignment
An attempt was made to assign a constant value to a bit field when the field is too small to hold the value. The following code segment demonstrates this problem:
% cat x.c struct bitfield { unsigned int block_len : 4; } bt; void test() { bt.block_len = 0xff; } % lint -u x.c "x.c", line 8: warning: precision lost in field assignment % cc -c -o x x.c %
This code compiles without error. However, because the bit field may be too small to hold the constant, the results may not be what the programmer intended and a run-time error may occur.
Recommended Action: Change the bit field size or assign a different constant value.
unsigned comparison with 0
An unsigned comparison is being performed against zero when the result is expected to be equal to or greater than zero.
The following program demonstrates this problem:
% cat z.c #include <stdio.h> unsigned offset = -1; main() { if (offset > 0) { [1] puts("unsigned comparison with 0 Failed"); return 1; } else { puts("unsigned comparison with 0 is Ok"); return 0; } } % cc -o z z.c % lint z.c "z.c", line 7: warning: unsigned comparison with 0? % ./z unsigned comparison with 0 Failed %
Unsigned comparisons such as this will fail if the unsigned variable contains a negative value. The resulting code may not be correct, depending on whether the programmer intended a signed comparison. [Return to example]
Add an
(int)
cast before
offset
in the
if
comparison.
Change the declaration of
offset
from
unsigned
to
int
.
6.12 Using Warning Class Options to Suppress lint Messages
Several
lint
warning classes have been added to the
lint
program to allow the suppression of messages associated with constants used
in conditionals, portability, and prototype checks.
By using the warning class
option to the
lint
command, you can suppress messages in
any of the warning classes.
The warning class option has the following format:
-wclass
[ class... ]
All warning classes are active by default, but may be individually deactivated by including the appropriate option as part of the class argument. Table 6-1 lists the individual options.
Note
Several
lint
messages depend on more than one warning class. Therefore, you may need to specify several warning classes for the message to be suppressed. Notes in Table 6-1 indicate which messages can be suppressed only by specifying multiple warning classes.
For example, because
lint
messages related to constants
in conditional expressions do not necessarily indicate a coding problem (as
described in
Section 6.11), you may decide to use the
-wC
option to suppress them.
The
-wC
option suppresses the following messages:
constant
constant
Because many of the messages associated with portability checks are
related to non-ANSI compilers and limit restrictions that do not exist in
the C compiler for Tru64 UNIX, you can use the
-wp
option to suppress them.
The
-wp
option suppresses the
following messages:
ambiguous
illegal
long
nonportable
possible
precision
precision
too
Although the use of function prototypes is a recommended coding practice
(as described in
Section 6.13), many programs do not include
them.
You can use the
-wP
option to suppress prototype
checks.
The
-wP
option suppresses the following messages:
function
mismatched
mix
old
use
Table 6-1: lint Warning Classes
Warning Class | Description of Class |
a |
Non-ANSI features. Suppresses:
|
c |
Comparisons with unsigned values. Suppresses:
|
d |
Declaration consistency. Suppresses:
|
h |
Heuristic complaints. Suppresses:
|
k |
K&R type code expected. Suppresses:
|
l |
Assign long values to non-long variables. Suppresses:
|
n |
Null-effect code. Suppresses:
|
o |
Unknown order of evaluation. Suppresses:
|
p |
Various portability concerns. Suppresses:
|
r |
Return statement consistency. Suppresses:
|
S |
Storage capacity checks. Suppresses:
|
u |
Proper usage of variables and functions. Suppresses:
|
A |
Activate all warnings.
Default option
in
|
C |
Constants occurring in conditionals. Suppresses:
|
D |
External declarations are never used. Suppresses:
|
O |
Obsolete features. Suppresses:
|
P |
Prototype checks. Suppresses:
|
R |
Detection of unreachable code. Suppresses:
|
6.13 Generating Function Prototypes for Compile-Time Detection of Syntax Errors
In addition to correcting the various errors reported by the
lint
program, we recommend adding function prototypes
to your program for both external and static functions.
These declarations
provide the compiler with information it needs to check arguments and return
values.
The
cc
compiler provides an option that automatically
generates prototype declarations.
By specifying the
-proto[is]
option for a compilation, you create an output file (with the same name as
the input file but with a
.H
extension) that contains the
function prototypes.
The
i
option includes identifiers
in the prototype, and the
s
option generates prototypes
for static functions as well.
You can copy the function prototypes from a
.H
file
and place them in the appropriate locations in the source and include files.