|
|
HP C/HP-UX Programmer's Guide: Workstations and Servers > Chapter 7 Using C Programming Tools 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:
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 )
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:
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. 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 )
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:
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
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:
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. 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:
Unused automatic variables cause the following message:
A function or external variable that is unused causes the message
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:
If functions or external variables are declared but never used or defined, lint responds with
followed by a list of variable and functions names and the names of files where they were declared. 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. 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:
The lint command also objects if automatic variables are set in a function but not used. The message given is:
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. 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:
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:
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. The C compiler allows a function containing both the statement
and the statement
to pass through without complaint. The lint command, however, detects this inconsistency and responds with the message:
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:
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,
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. The -p option of lint aids the programmer is writing portable code in four areas:
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
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:
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:
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. The -s option of the lint command checks for the following portability considerations:
The checks made for pointer alignments are exactly the same as for the -p option. The warning for these cases is:
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:
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:
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:
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,
where the * has no effect. The statement is equivalent to "p++;". In cases like this, the message
is sent. The treatment of unsigned numbers as signed numbers in comparison causes lint to report the following:
The following code would produce such a message:
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
lint's response is:
To avoid operator precedence confusion, lint encourages using parentheses in expressions by sending the message:
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:
The -h option suppresses lint diagnostics of strange constructions. The lint libraries are arranged for standards checking. For example,
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. |
|