HPlogo HP C/HP-UX Programmer's Guide: HP 9000 Computers > Chapter 7 Using C Programming Tools

Using lint

» 

Technical documentation

Complete book in PDF

 » Table of Contents

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:

Title not available (Using lint )

-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 defects; leaves external information in files suffixed with .ln.

-h

Does not apply heuristics (which attempt to detect defects, 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.

lint also recognizes the -LINTLIBRARY the HP C -Wp option. The lint -LINTLIBRARY option is equivalent to using lint comment /*LINTLIBRARY*/ in source files. lint also recognizes the -Wp option and passes named arguments to the preprocessor.

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.

Title not available (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 defect, 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 “Directives ”.

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 defects 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;
int i; /* 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 defect.

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.

© Hewlett-Packard Development Company, L.P.