LLIINNTT RReeffeerreennccee MMaannuuaall by J. A. Gardner Thinkage Ltd. 85 McIntyre Drive Kitchener, Ontario Canada N2R 1H6 Copyright 1995 by Thinkage Ltd. Thinkage Ltd. LINT Reference Manual TTaabbllee ooff CCoonntteennttss 11.. IInnttrroodduuccttiioonn........................................................................................22 22.. LLIINNTT DDiirreeccttiivveess..................................................................................33 33.. LLIINNTT OOuuttppuutt..........................................................................................44 Message Classes........................................4 Output Grouping........................................6 Type Information.......................................7 44.. LLIINNTT CCoonnvveennttiioonnss................................................................................99 55.. UUnnuusseedd DDeeffiinniittiioonnss aanndd DDeeccllaarraattiioonnss........................................1100 Marking Symbols As Used...............................10 66.. UUnnddeeffiinneedd oorr UUnnddeeccllaarreedd DDaattaa OObbjjeeccttss......................................1111 77.. UUnnrreeaacchhaabbllee CCooddee..............................................................................1122 Marking Unreachable Code..............................12 88.. FFuunnccttiioonn RReettuurrnn VVaalluueess..................................................................1133 Ignoring Return Values................................14 99.. TTyyppee CChheecckkiinngg....................................................................................1155 1100.. FFuunnccttiioonn DDeeccllaarraattiioonnss..................................................................1177 The #pragma varargs Directive.........................18 The #pragma argsused Directive........................19 1111.. AAlltteerrnnaattee FFoorrmmss..............................................................................2211 1122.. MMiisscceellllaanneeoouuss NNootteess......................................................................2233 1133.. EExxttrraa CCoommppiilleerr WWaarrnniinnggss..............................................................2244 Alignment Problems....................................24 1144.. TThhee LLIINNTT CCoommmmaanndd LLiinnee..................................................................2266 Abbreviating Options:.................................30 Other Ways to Use LINT................................30 Summary Files.........................................30 LINT Libraries........................................31 Review of Inputs and Outputs..........................32 Multiple Definitions..................................32 Configuration Files...................................33 November, 1995 Page i LINT Reference Manual Thinkage Ltd. CChhaapptteerr 11 IInnttrroodduuccttiioonn LINT is a program that examines C source code and makes note of "irregularities" in the code. When LINT was first implemented, its primary function was locating bugs and inefficiencies. However, as the C programming language spread to a variety of machines and systems, LINT was enhanced to locate deviations from the strict definition of C. The ANSI standard for C now provides the "official" definition of C. However, the ANSI standard does not entirely describe the behavior of C implementations, because the standard allows certain operations to be performed in a system-dependent way. If a program is written in conformance with the ANSI standard, avoiding such system- dependent features, we say that the program is written in _S_t_r_i_c_t_ _C. Ideally, all programs should be written in Strict C, since these programs are maximally portable. One of the major functions of LINT is to detect code constructs which do not conform with Strict C. Such constructs are often valid and can be used in working programs, but they are not truly portable and may be indications of loose programming style. LINT shows where you have written non-portable code; for portability, you should try to remove such code. Before we begin, we should note that it is inevitable that LINT will miss some problems and will also complain about code that turns out to be valid. The designers have tried to chart a course between too much laxness (which may miss significant irregularities) and too much nit-picking (which produces quantities of irrelevant output that you will likely ignore). Thus we have designed this version of LINT to report situations that are _u_s_u_a_l_l_y signs of errors. While odd constructions and unusual programming style can confuse LINT from time to time, the majority of material that LINT locates should deserve the programmer's attention. Page 2 November, 1995 Thinkage Ltd. LINT Reference Manual CChhaapptteerr 22 LLIINNTT DDiirreeccttiivveess LINT understands all the usual C preprocessing directives (e.g. ##iinncclluuddee,, ##ddeeffiinnee,, etc.). In addition, LINT recognizes a number of other directives that have the same sort of format: #pragma aligned #pragma argsused #pragma notreached #pragma optresult #pragma used #pragma varargs These directives tell LINT about special features of your source code and allow LINT to provide more meaningful diagnostic messages. The usage of each LINT directive is explained later in the manual. ANSI C compilers should not reject these special LINT directives; the ANSI standard says that C compilers are supposed to ignore any ##pprraaggmmaa directives they do not understand. However, non-ANSI C compilers may issue diagnostic messages for these ##pprraaggmmaa directives, and even some ANSI C compilers may issue warnings about unrecognized ##pprraaggmmaas. November, 1995 Page 3 LINT Reference Manual Thinkage Ltd. CChhaapptteerr 33 LLIINNTT OOuuttppuutt LINT generally produces quite a lot of output. By default the output is written to the terminal, but it can be redirected to a file using the standard output redirection constructions on the LINT command line. The first lines of output from LINT are diagnostic messages comparable to those that might be produced by a C compiler. These diagnostics describe easily detected things like syntax errors. Following this comes output that is unique to LINT. Most lines in the output have the form filename,lineno: class: text where filename is the name of one of the source files that LINT is scanning and lineno is a line number within that file. The class field tells the type of problem found; see "Message Classes" below for more information. The text part of the message provides specific information about the problem. Some lines may have the form libname: class: text where libname is the name of a LINT Library. For more information on LINT libraries, see the last section of this manual. MMeessssaaggee CCllaasssseess Each message produced by LINT is labelled with a string indicating what kind of problem the message describes. The following message classes are recognized: Error: Same as error messages produced by the compiler: code so incorrect that there is no way to generate any sort of object code. Warning: Marks a construct that is invalid but a compiler could still generate some kind of object code. For example, the ANSI standard does not allow assignments between pointers of different types, but most compilers can Page 4 November, 1995 Thinkage Ltd. LINT Reference Manual still generate sensible object code for such an operation. Unusual: Marks a construct which is valid, but which is not often seen in C programs. For example, i=i; is valid but suspicious, possibly indicating some problem in your code. Note: Marks a construct which is invalid but always works properly on the current machine. For example, printf("%ld",1); is invalid since %ld requires a lloonngg argument but 1 is just iinntt. However, this always works properly on machines where lloonngg and iinntt are the same size. MachDepd: Marks a valid construct whose behavior is machine- dependent. For example, the result of (-7/2) is machine-dependent, since the ANSI standard allows this kind of division to truncate either towards or away from zero. Extension: Marks a construct that is an extension to the ANSI standard. Efficiency: Marks code that has been written in a particularly inefficient way, or using constructs that are likely to execute slowly. NotMinimal: Marks a construct which is valid ANSI C but may not be accepted by older C compilers (e.g. vvooiidd ** pointers). Info: Provides cross-reference information while using LINT. IntrnErr: An internal error in LINT itself (for example, a table overflow). November, 1995 Page 5 LINT Reference Manual Thinkage Ltd. OOuuttppuutt GGrroouuppiinngg LINT output is grouped according to the functions of the source code. The first line of a group of messages gives the name of a function or an external variable. After that come all the messages pertaining to that function or variable. The messages end with a blank line, followed by the group of messages for the next function or variable. Groups are sorted in alphabetical order according to the name of the function or variable. The first line of every function group gives the name of the function and the type of value that the function returns. If LINT has found a definition for the function, the first line of the function group is Function "NAME" returns "TYPE". where NAME is the name of the function and TYPE is the type of value that the function returns. If LINT can't find a definition for the function, LINT looks at the first _r_e_f_e_r_e_n_c_e to the function that appears in the source code and prints Function "NAME" is assumed to return "TYPE". where TYPE is the type suggested by the way in which the function is used. In keeping with the rules of C, LINT assumes that a function returns iinntt if the function is not explicitly declared to have a different type. If the first reference to the function does not use a return value from the function, the message is Function "NAME" assumed to return no value. If LINT scans a function definition and finds that there are no rreettuurrnn statements that return a value, LINT outputs the message Function "NAME" returns no value. You should distinguish between this message and Function "NAME" returns void. Page 6 November, 1995 Thinkage Ltd. LINT Reference Manual The vvooiidd message appears when a function is explicitly declared with the vvooiidd keyword. The "no value" message appears when a function definition has no rreettuurrnn statements. The first appearance of an external variable is treated in much the same way as the first appearance of a function. You will see a message like External "NAME" is "TYPE". or External "NAME" is assumed to be "TYPE". With one exception, the messages we have described so far are always issued, whether or not there are errors. The exception is when a symbol appears in a LINT library (described later on) and is not referenced in normal source code. Messages about library functions and variables only appear if the symbol is used in source code. Other messages in LINT output describe situations that may be errors. These messages refer to difficulties within the function with which they are grouped. TTyyppee IInnffoorrmmaattiioonn At the end of its output, LINT displays a block of information describing the types of the program. A typical line of output is filename,lineno: type where filename is the name of the file where the type was defined and lineno is the line number where the definition began. LINT provides information about any ttyyppeeddeeffs, enumerated types, structures, and/or unions that were involved in the messages produced. This lets you locate the definitions of these types. If a type appears twice in this list, it usually means that there is more than one definition for the same type and the types are not assignment-compatible. LINT also checks for structures and unions which are used in functions and which have been incompletely defined. Incomplete definitions are acceptable as long as there is a complete definition somewhere. All complete definitions November, 1995 Page 7 LINT Reference Manual Thinkage Ltd. have to be identical. If complete definitions conflict with each other, LINT issues a diagnostic beginning with filename : type where filename is the name of a file where the type was used and found to conflict with another definition. Page 8 November, 1995 Thinkage Ltd. LINT Reference Manual CChhaapptteerr 44 LLIINNTT CCoonnvveennttiioonnss A function is _d_e_f_i_n_e_d by the function header that actually starts the function. This tells the type of value that the function returns and describes the arguments of the function. An external variable is _d_e_f_i_n_e_d by a declaration for the variable that is outside the scope of all functions and that does not include the keyword eexxtteerrnn. A function is _d_e_c_l_a_r_e_d by a declaration or function call inside another function. An external variable is _d_e_c_l_a_r_e_d by a declaration that includes the keyword eexxtteerrnn. Such a variable declaration does not allocate space for the variable; it merely describes the type of the variable and presumes that the variable is defined elsewhere. A variable is _s_e_t if it is assigned a value or if a pointer to the variable is taken. Similarly, a variable is _u_s_e_d if its value is used or if a pointer is taken. (You might wonder why taking a pointer marks a variable as both "set" and "used". The answer is that once a pointer to a variable is taken, LINT can't keep track of assignments or uses of the variable through the pointer. Once the pointer is taken, LINT can only assume that the data object may have been both set and used.) November, 1995 Page 9 LINT Reference Manual Thinkage Ltd. CChhaapptteerr 55 UUnnuusseedd DDeeffiinniittiioonnss aanndd DDeeccllaarraattiioonnss One of the easiest problems for LINT to find is a variable or function that is defined but not used or called in the rest of the program. Such items can usually be deleted, since they are not performing any function in the program. The diagnostic messages for such situations are listed and explained below. Function "NAME" is never called. The given function was defined in the source code but never called. External "NAME" is never used. The given external variable was defined but never used. External "NAME" is defined but never set or used. This is essentially the same as the previous message. External "NAME" is set but never used. The given external variable was assigned a value, but then was never used for anything. Messages are _n_o_t generated if a symbol in a LINT library is unused. MMaarrkkiinngg SSyymmbboollss AAss UUsseedd Sometimes, you may intentionally declare a variable without using it. For example, suppose a variable is only used inside a ##iiff block and that block of code is not compiled because the ##iiff condition is not met. LINT would normally issue an error message for this condition, but you might not consider this situation an error. To avoid this sort of message, you can add the LINT directive #pragma used NAME NAME NAME ... to your source code. This tells LINT that the names listed in the directive are used by your program, even if it doesn't look like they are. Page 10 November, 1995 Thinkage Ltd. LINT Reference Manual CChhaapptteerr 66 UUnnddeeffiinneedd oorr UUnnddeeccllaarreedd DDaattaa OObbjjeeccttss LINT uses a simple-minded way to find places where undefined variables are used: a variable is assumed to be undefined if a statement using the variable appears in the code before the variable is set. Of course, it is possible to construct programs where this approach fails. With the use of spaghetti-like ggoottoos, the top-down technique can be outwitted. Because static and external variables are automatically initialized to zero by the compiler if they are not initialized explicitly, LINT does not pick up problems with these variables. The following diagnostics pertain to data objects that are used before they are set, defined, or declared. Function "NAME" is called but never defined. The source code contains a call to the given function, but the function is not defined anywhere in the code. "NAME" is set but never defined. The given variable has been assigned a value, but a proper definition does not appear in the source code. "NAME" is used but never defined. The value of the given variable was used, but the variable was never defined. "NAME" is used but never defined or set. The value of the given variable has been used, but the variable was neither defined nor set. "NAME" is defined and used but never set. The given variable is defined and used, but never set. This message is only issued for local variables, since all external variables are automatically initialized to zero (if no explicit initialization is specified). November, 1995 Page 11 LINT Reference Manual Thinkage Ltd. CChhaapptteerr 77 UUnnrreeaacchhaabbllee CCooddee LINT attempts to detect parts of the source code that cannot be reached (for example, unlabelled statements following a ggoottoo). It also attempts to find loops that can never be exited from the bottom, such as wwhhiillee((11))...... At the same time, LINT finds loops that cannot be entered from the top. The message that is issued for detected unreachable code is Non reachable code at "TEXT". where TEXT is the source code that cannot be reached. MMaarrkkiinngg UUnnrreeaacchhaabbllee CCooddee LINT cannot detect functions which are called and never return (for example, ones that terminate execution via exit). This means that it is possible for LINT to miss some unreachable code, as in g() { exit(-1); } f() { ... g(); /* everything that follows * is unreachable */ ... } To mark this kind of situation, you can use the LINT directive #pragma notreached When this directive appears in your source code, LINT regards any source code following the directive as unreachable, up to the end of the block or the next statement label. Appropriate diagnostic messages will be issued. Page 12 November, 1995 Thinkage Ltd. LINT Reference Manual CChhaapptteerr 88 FFuunnccttiioonn RReettuurrnn VVaalluueess LINT reports functions that contain both return( expression ); and return; This kind of situation usually results in errors (since the calling function may assume a value is being returned but one of the rreettuurrnn statements does not return a value). Correspondingly, LINT makes note of whether or not a call to a function makes use of a return value from the function. If the caller expects a value but the function does not return one, it is clearly a bug. If the function returns a value but the the caller does not use it, it could be an error, an inefficiency, or sloppy programming style. If a function definition contains no rreettuurrnn statements that return a value, LINT regards the function type as iinntt unless it is explicitly declared differently. If LINT finds a reference to the function before it finds the function definition, it assumes that the function returns a value unless the function is explicitly declared as vvooiidd. Programmers who are used to looser controls than this will find themselves with a large number of diagnostic messages. The messages related to function return values are listed below. Value is used but none returned. A function did not return a value, but the statement that called the function behaved as if a value was returned. Function NAME has no return value A function was defined as returning a value (the function is not vvooiidd)) but it did not contain a return(expression) statement. Return value ignored. The given function contains a November, 1995 Page 13 LINT Reference Manual Thinkage Ltd. return(expression); statement, but the caller never uses the return result. Return value sometimes ignored. This is similar to the last situation, except that the return result is sometimes used, sometimes not. IIggnnoorriinngg RReettuurrnn VVaalluueess There is always the possibility that you want to write a function whose return value can be ignored. The C library has several functions whose return value is superfluous. For example, strcpy(A,B) copies string B into string A and returns a pointer to A. This is unnecessary, since the caller already has a pointer to A. LINT lets you mark functions with optional return values by using a directive similar to the ##directives of the C preprocessor. #pragma optresult can be placed immediately before the definition of a function that returns an optional result. LINT then recognizes that this function returns a result that can be ignored; LINT does not give error messages if the result is ignored. Page 14 November, 1995 Thinkage Ltd. LINT Reference Manual CChhaapptteerr 99 TTyyppee CChheecckkiinngg LINT enforces stronger type-checking than most compilers do. In expressions where different types of data are intermixed, LINT observes the strict conventions for conversions of data and requires that everything else be properly cast. LINT checks for type incompatibilities in three places: (a) in the arguments passed to functions (b) in the return values received by functions (c) in structure manipulations For fullest type-checking, the code should use prototypes wherever possible. LINT also checks for situations in which some function calls take place with a prototype in scope while others do not. When arguments are passed to functions, LINT issues a diagnostic if the argument type passed by the caller differs from the argument type expected by the called function. Similarly, LINT complains if the argument type returned by the called function differs from the argument type expected by the caller. The messages associated with this situation are given below. Argument N is "TYPE1", but declared as "TYPE2". When the given function was called, the caller passed a value of type TYPE1 for argument number N, but the called function expected a value of TYPE2. For example, you might see Argument 2 is "int", declared "unsigned int". This indicates that the caller passed an integer value as the second argument of the function, but the called function expected an unsigned integer. Argument N is "TYPE", but declared as a different "TYPE" This is an odd situation where the definition and a declaration give the argument different types, but the strings used to print out TYPE turn out to be the same. For example, suppose that a function has a local ssttrruucctt X, but there is also an external ssttrruucctt X which is not compatible with the local one. If the program invalidly tries to combine external and local variables of type X, you get the above message; even though the types have the same name, they are different. The same November, 1995 Page 15 LINT Reference Manual Thinkage Ltd. sort of situation may happen with other LINT error messages. "NAME" is redeclared as function type "TYPE". When NAME was first declared, it was said to return a value of one type. Now NAME has been declared or used as a function returning a different type of value. "NAME" declared as returning "TYPE" The function NAME has been declared as returning a TYPE that is different than its definition. "NAME" declared as "TYPE" The variable NAME has been declared with a TYPE that is different than its definition. "NAME" is redefined as function. NAME was originally declared as a variable, but is now being defined as a function. LINT also issues a message whenever a data object is implicitly shortened. For example, suppose we have long l; int i; /* stuff */ i = l; The C compiler automatically shortens the long "l" and assigns the result to "i". However, LINT flags this as a potential problem (since different integer sizes on different machines may affect how this works). No error message is issued if the conversion is done explicitly, as in i = (int) l; As a final note about type-checking, LINT occasionally gets some complicated types wrong. For example, warnings about structures that contain arrays of structures do not give the right type (namely ssttrruucctt). The same problem occurs when LINT is not given the internal structure of a ssttrruucctt. For example, it is valid for a source module to declare struct ABC *ptr; without describing the internal structure of the ABC ssttrruucctt. In such cases, LINT does not have enough information to determine if code is valid, so the warning messages may not be entirely accurate. Page 16 November, 1995 Thinkage Ltd. LINT Reference Manual CChhaapptteerr 1100 FFuunnccttiioonn DDeeccllaarraattiioonnss LINT compares all the available prototype declarations for a function to make sure that the prototypes match _e_x_a_c_t_l_y. For example, LINT notes situations where one prototype gives vvooiidd ** as the type of an argument while another types the same argument as cchhaarr **. In practice, there is no difference between these two pointer types; however, LINT makes note of the situation because it may be indicative of an error. In addition to checking that the argument types expected by a called function match the argument types passed by the caller, LINT also checks that the _n_u_m_b_e_r of arguments expected by the called function matches the number of arguments passed by the caller. If there is a mismatch, it prints Called with N arguments, requires M where N is the number of arguments that the caller passes and M is the number of arguments that the function expects. Whenever possible, LINT checks to see that argument declarations in function prototypes agree exactly with the declarations in the function definition. If the declarations do not agree, LINT outputs Prototype argument N is "TYPE" but declared as "TYPE" LINT expects argument declarations to match exactly. For example, the vvooiidd ** type is considered assignment-compatible with all pointer types and therefore there is not a conflict between vvooiidd ** and another pointer type. Nevertheless, LINT points out the difference, simply to warn you that there seems to be a discrepancy in your code. Finally, LINT makes sure that the number of arguments in a prototype declaration matches the number in the function definition. If not, LINT prints Prototyped with N arguments, but requires M where M and N are both integers. November, 1995 Page 17 LINT Reference Manual Thinkage Ltd. TThhee ##pprraaggmmaa vvaarraarrggss DDiirreeccttiivvee In earlier versions of C it was valid to pass more arguments than the function definition specifies or to pass fewer arguments. This is not valid in ANSI C unless you use the "..." construct in the prototype; however, older code may still make use of such calling sequences and most compilers still handle the situation properly. In order to handle all the possibilities of this situation, LINT introduces the ##pprraaggmmaa vvaarraarrggss directive. The directive has two forms. #pragma varargs N indicates that the next function to be defined can take a variable number of arguments but must have a minimum of N arguments. For example, we might write #pragma varargs 3 int Mini(N,a,b,c,d); int N,a,b,c,d; { .... to declare a function Mini that must take at least three arguments and can have more. In this case, LINT does not issue an error message if you have at least three integer arguments present. With this form of the ##pprraaggmmaa vvaarraarrggss directive, LINT typechecks all the arguments that are present. In the above example, LINT ensures that all the arguments being passed are integers. The second form of the directive is #pragma varargs N M where both N and M are integers. This indicates that the next function to be defined must have a minimum of N arguments, and LINT should typecheck up to M arguments if they appear. For example, you can imagine a printf-like function that takes a format string plus one or more values to print. This could be preceded with #pragma varargs 2 1 showing that the function must always have two arguments (a format string and at least one output value) but that only Page 18 November, 1995 Thinkage Ltd. LINT Reference Manual the first argument should be typechecked (since the output value(s) need not have a fixed type). The directive can also take the form #pragma varargs printf #pragma varargs scanf These forms may be used to indicate functions that take format strings comparable to the strings of printf and scanf (respectively). LINT compares the placeholders in the format string to the types of the arguments that follow the format string, and reports any conflicts between types. For example, it tells you if the argument corresponding to a %s placeholder is an iinntt value (incompatible with %s). TThhee ##pprraaggmmaa aarrggssuusseedd DDiirreeccttiivvee Some functions are able to use all the arguments they are passed without actually referring to every argument by name. For example, consider a function Max10 which can accept up to 10 iinntt arguments and return the value of the largest argument. The first argument passed to Max10 tells how many values have actually been passed. This could be defined with int Max10(N,a,b,c,d,e,f,g,h,i) int N,a,b,c,d,e,f,g,h,i; { int j,m,*p; m = a; p = &a; for (j=1; j < N; ++j) if (p[j] > m) m = p[j]; return(m); } As you can see, the function does not refer to the parameters b, c, etc. by name. However, it does look at their values, since it walks through the stack using offsets from a. Therefore the values are used. This sort of coding practice is a violation of the ANSI standard. The standard doesn't let you use subscripts to access memory locations outside the bounds of a single object, so p[j] is invalid if j is not zero. On the other hand, many compilers still accept code like this and older programs may use it. November, 1995 Page 19 LINT Reference Manual Thinkage Ltd. For such programs, you can avoid some diagnostic messages from LINT by putting the LINT directive #pragma argsused on a line preceding the function, as in #pragma argsused int Max10(N,a,b,c,d,e,f,g,h,i) ... This tells LINT that the function uses all its arguments, even if it doesn't appear to. Page 20 November, 1995 Thinkage Ltd. LINT Reference Manual CChhaapptteerr 1111 AAlltteerrnnaattee FFoorrmmss For compatibility with the Bell Labs' version of LINT, this version of LINT may accept some directives in the form of comments. These are only recognized if the +ControlComments option is specified on the LINT command line. /*VARARGSN*/ (where N is an integer) is automatically converted to #pragma varargs 0 N For example, /*VARARGS3*/ is equivalent to #pragma varargs 0 3 In addition, /*VARARGS*/ (with no value N) is equivalent to #pragma varargs 0 In addition to VARARGS, the comment /*ARGSUSED*/ is automatically converted to #pragma argsused and the comment /*NOTREACHED*/ is equivalent to #pragma notreached In all cases, the comment form may not contain white space (blanks, tabs, or new-lines). All alphabetic characters must be in upper case and there can be nothing November, 1995 Page 21 LINT Reference Manual Thinkage Ltd. else in the comment except the keyword and any number that should follow. Page 22 November, 1995 Thinkage Ltd. LINT Reference Manual CChhaapptteerr 1122 MMiisscceellllaanneeoouuss NNootteess LINT always uses the full name of functions and variables, and always distinguishes between upper and lower case letters. This is the way that C compilers are supposed to work as well. However, some compilers or loaders truncate long names to a certain number of characters, and some compilers or loaders do not distinguish between the case of letters in names. For this reason, LINT issues the following warnings. NAME1 and NAME2 not unique in first N caseless characters. N is the number of characters to which names may be truncated to meet loader requirements. NAME1 and NAME2 not unique without case distinction. This applies to names like VAR, var, and Var used in the same program. LINT detects redeclaration of functions and variables defined outside the scope of any function. The set of messages dedicated to this kind of problem are given below. NAME redeclared. A given variable has been invalidly declared in a second place. NAME retyped as "TYPE". A given variable has been used as if it had a type different from its declared type. NAME redeclared with type "TYPE". The given variable appears in a new declaration with a different type than it previously had. NAME is redefined as function. A name that was previously given to an external variable has now been given to a function. LINT assumes that sshhoorrtt integers have a length of 16 bits and that lloonngg integers have a length of 32 bits, regardless of what length these data types have on your machine. The reason is that short and long integers are guaranteed to have at least these lengths on all machines. Your hardware may allow longer integers (for example, 36 bits) but code that uses the increased size is not portable to machines with smaller words. For the same reason, LINT assumes that all characters are 8-bit signed quantities, even though they may be longer or unsigned on your machine. November, 1995 Page 23 LINT Reference Manual Thinkage Ltd. CChhaapptteerr 1133 EExxttrraa CCoommppiilleerr WWaarrnniinnggss In addition to the diagnostics produced especially for LINT, the LINT output also contains all the error and warning messages produced by the parsing phase of the C compiler. Most of these are self-explanatory, but there are a few that deserve further comment. Constant "CONSTANT" too large for "TYPE". As noted earlier, LINT assumes short integers are 16 bits long and long integers are 32 bits long. Therefore you may get this message, even though a short or long integer type on your machine is actually long enough to hold a given constant. Character constant with no characters. Some compilers do not accept a null character constant. Your compiler may accept such constants, but LINT still complains about the construct. Constant valued logical expression. This refers to situations like while (1) { ... } AAlliiggnnmmeenntt PPrroobblleemmss In addition to the error messages listed above, you may receive the warning Possible alignment problems with cast When casting data of one type to data of another, alignment problems may occur. For example, there may be difficulties in casting a character pointer to an integer pointer if the character pointer is not aimed at a word boundary. At times, however, you may have taken pains to make sure that this kind of alignment problem will not occur. In particular, you may have created a function that returns a value or pointer that is suitably aligned for any use. This is true of functions like malloc; the value that malloc returns is officially a vvooiidd ** pointer, but it is suitably aligned to store any sort of data. If you have a function that returns a suitably aligned pointer, you can tell LINT by placing #pragma aligned Page 24 November, 1995 Thinkage Ltd. LINT Reference Manual in front of the start of the function declaration. This tells LINT that the function itself deals with any alignment problems. November, 1995 Page 25 LINT Reference Manual Thinkage Ltd. CChhaapptteerr 1144 TThhee LLIINNTT CCoommmmaanndd LLiinnee _S_y_n_t_a_x_: tlint [file] [option]* (+|-)ControlComments (-) (+|-)Declarations (-) (+|-)Keep (-) (+|-)StandardLibrary (+) (+|-)Verbose (-) (+|-)Wide (-) Configuration=file CrossReference=keyword Define=name=value Include=directory INSTallation=file Library=lib libraryName=string Output=file Output+=file StandardInclude=directory StandardLibrary=name Summary=file Target=keyword indeX=file _E_x_a_m_p_l_e_s_: tlint myfile tlint x=files o=incls ln=proj def=PROJECT=1 _O_p_t_i_o_n_s_: file is a source file containing C code. The other options on the command line determine whether LINT scans this file for problem spots, or uses the file to create a summary or an entry in a LINT library. indeX=file gives the name of a text file. Each line in this text file should contain the name of one C source file. LINT checks each of these source files individually. In addition to a source file name, a line in an index file may specify ControlComments, Configuration=, Include= and Define= options. These options only apply to the source file named on the same line. For example, if the line myfile define=VERSION=1 appeared in an index file, LINT would use the given option when examining myfile but not for other files named in the index file. When processing an index line, LINT normally uses all the options appearing on the main command line, followed by the options specified on the index line. As a special case, however, Include= options on a line in an index file are used before any Include= options on the LINT command line. Only one indeX= option may appear on the command line. Page 26 November, 1995 Thinkage Ltd. LINT Reference Manual Configuration=file specifies a configuration file for LINT. For more information on configuration files, see below. +ControlComments indicates that control comments of the type /*VARARGS*/ should be processed. The default is -ControlComments, in which case such comments are ignored. A ControlComments option on a line in an index file overrides any ControlComments option on the main LINT command line. CrossReference=keyword indicates that LINT output should include a cross- reference table that shows where symbols are defined, referenced, set, and used. (By default, cross- references are not provided.) Possible values for the keyword are: All - cross-references all symbols; External - only cross-references external symbols. +Declarations may be used when creating a LINT library or summary file. With this option, LINT treats every file scope declaration as if it were a definition for the variable, instead of a simple reference. Define=name=value has the same effect as #define name value in the C source code. The option indicates that "name" should be replaced with "value" (as text) wherever it appears in the source code being examined. If "value" contains blanks or tab characters, it should be enclosed in double or single quotes. Include=directory is the same as the Include= option for the C compiler. When LINT tries to find quoted include files, as in #include "file" it begins by searching the given directory for the file. If the file is not found there, LINT searches November, 1995 Page 27 LINT Reference Manual Thinkage Ltd. any directory named in StandardInclude= options, and finally searches the directory that contains the source file being examined. Any number of Include= options may be specified. Directories are searched in the order given on the command line. INSTallation=file tells LINT where to find the installation file. The installation file tells where various software components have been installed. For more information, see the section on _I_n_s_t_a_l_l_a_t_i_o_n_ _F_i_l_e_s below. If you do not specify an INSTallation= option on the command line, LINT checks for an environment variable named LINT_INST and uses its value as the name of the installation file. If this environment variable does not exist, LINT uses the default installation file. +Keep does not delete intermediate files left by the preprocessor and the LINT steps. Library=lib names a LINT library that should be used when checking source code. Any number of Library= options may appear on the command line. By default, LINT automatically includes LINT libraries of standard C functions (e.g. printf) so that such functions are always recognized. libraryName=string is used when creating a LINT library. See below for more details. Output=file is used when creating a LINT library or summary file (see below). The output overwrites the file's current contents. Output+=file is the same as Output=file, except that output is written to the end of the current contents of the specified file, rather than overwriting what the file already holds. StandardInclude=directory is the same as the StandardInclude= option for the C compiler. When LINT tries to find include files whose names are enclosed in angle brackets, as in #include Page 28 November, 1995 Thinkage Ltd. LINT Reference Manual it begins by searching the given directory for the file. If the file is not found there, LINT searches directories named in Include= options, and finally searches the directory that contains the source file being examined. Any number of StandardInclude= options may be specified. Directories are searched in the order given on the command line. StandardLibrary=name asks LINT to include the standard library indicated by "name". The following names are recognized: C - the standard C library. This is included automatically, unless -StandardLibrary is specified. -StandardLibrary does not include the standard C library routines. Summary=file states that the given file is a summary file that should be used as input to the LINT operation. See below for more on summary files. Target=keyword controls the kind of problem-checking you want to do. The following keywords are recognized. Host - describes any problems that may arise if the program is run on the host machine (i.e. the machine where you are running LINT). This is the default. Extensions - points out any extensions to C that might have been used, as well as any machine-dependencies in the code. It also describes the problems detected with Target=Host. Minimal - points out any features that may cause problems if you port this program to a non-ANSI compiler. This will make note of all ANSI features used. It also describes the problems detected with Target=Extensions. +Verbose prints out the name of the file being examined. The default is -Verbose. +Wide prints output in a format that is 132 columns wide. The default is -Wide, which prints in an 80-column format. November, 1995 Page 29 LINT Reference Manual Thinkage Ltd. _A_b_b_r_e_v_i_a_t_i_n_g_ _O_p_t_i_o_n_s_: The option keywords given above can be abbreviated by omitting any or all of the letters shown in lower case. For example, CrossReference=All may be abbreviated to crossref=all cref=all cr=all cr=a and so on. When entering option keywords, you may type letters in upper, lower, or mixed case; the use of upper and lower case in this documentation is simply to show what letters are and aren't required. _O_t_h_e_r_ _W_a_y_s_ _t_o_ _U_s_e_ _L_I_N_T In addition to checking C code for irregularities, LINT can: (a) Extract a summary file of information that can be used in other LINT operations. (b) Create a LINT library. Summary files and LINT libraries are discussed below. _S_u_m_m_a_r_y_ _F_i_l_e_s A summary file contains a "summary" of your source code: the names and types of all the external variables and functions defined or referenced in the code, plus any other information LINT may need when checking the code (such as the declared types of function parameters). Summary files also record any error messages that might be issued by the C compiler when parsing the source code. All of this information is stored in a special format that is not directly readable by humans. To create a summary file from a normal source code file, use the Output=file option, as in tlint src1.c output=summ You can add more material to the same summary file using Output+=file, as in Page 30 November, 1995 Thinkage Ltd. LINT Reference Manual tlint src2.c output+=summ This appends new material to the existing contents of the summary file. When LINT creates a Summary file, LINT only summarizes your source code and checks for syntax errors. It does not check for such problems as non-portable constructs or type mismatches. However, you can run a summary file through LINT again to do standard type-checking. For example, tlint srcfile output=lf tlint summ=lf creates a summary file, then uses the information in the summary file to see if types match in symbol references and definitions. The reason for creating summary files is the same as the reason for breaking up the source code of your program into several source files: it is easier to deal with source code in small pieces than in one big hunk. Some users may keep a summary file for every source file. If the code in one source file is changed, you can create a summary file from that source file, then run all the summary files of the program through LINT to see if the change has caused any problems. This is much faster than using LINT on all the raw source code. _L_I_N_T_ _L_i_b_r_a_r_i_e_s A LINT library is similar to a summary file, in that it contains a summary of C source code. However, LINT libraries are intended to parallel the way that object libraries work. To create a LINT library, specify both the Output= option and the libraryName= option on the LINT command line. For example, tlint file output=mylib libname="abc" creates a LINT library named abc in the file mylib. This name is used in LINT diagnostic messages related to symbols found in the LINT library. Using LINT in this way only generates minimal messages; full messages are printed when you actually use the LINT library. To use a LINT library, specify the Library= option on the LINT command line, as in November, 1995 Page 31 LINT Reference Manual Thinkage Ltd. tlint myfile library=mylib When LINT finds that myfile contains a reference to an undefined symbol, LINT checks the information in the given LINT library to see if the symbol is defined there. This works just like compiling a module while referring to an object library. No error occurs if a symbol in the LINT library has the same name as a symbol in the source file; the source file symbol is the one that is used. Functions should only be placed in a LINT library when you are sure they contain no errors. LINT does not look for errors when it is creating a LINT library. _R_e_v_i_e_w_ _o_f_ _I_n_p_u_t_s_ _a_n_d_ _O_u_t_p_u_t_s To specify a file as an input, simply give the file's name. To specify a summary file as input, use Summary=file. To specify a LINT library as input, use Library=file. LINT uses all of the contents of a source file or a summary file; it only uses library entries if they are referenced by source code or a summary file. An index file contains partial command lines to be used by LINT in its operations. These command lines can name source files as input, but not summary files or LINT libraries. When both an Output= and libraryName= option are specified, LINT creates a LINT library. If only Output= is specified, LINT creates a summary file. If Output= is not specified, LINT examines a source file or summary file for problem spots and writes its diagnostics to the standard output. _M_u_l_t_i_p_l_e_ _D_e_f_i_n_i_t_i_o_n_s If LINT finds two definitions for the same function or external variable, it always outputs a diagnostic message. If the two definitions are both in normal source code, LINT arbitrarily chooses the first definition it finds as the "correct" definition, and issues diagnostics for any later deviations from this definition. If one of the two definitions is in a LINT library and the other is in normal source code, LINT chooses the non-library version as the "correct" definition. In this way, a definition in normal source code overrides a library definition. Page 32 November, 1995 Thinkage Ltd. LINT Reference Manual _C_o_n_f_i_g_u_r_a_t_i_o_n_ _F_i_l_e_s A configuration file consists of a series of directives that control the behavior of LINT. The possible directives are explained below. define name string has the same format and purpose as a ##ddeeffiinnee directive in normal C code. It creates a manifest or macro with the given value. inline includefile lets you simulate an include file. When LINT finds an inline directive, it begins to gather input lines up until the first line consisting of only a '#' character. For example, in inline sim.h extern int junk1; extern int junk2; # LINT collects the two declarations and associates them with the name "sim.h". If a program contains the directive, #include LINT takes the gathered text and includes it at that point in the program, as if it had come from an included file. map includename1 includename2 says that all references of the form #include includename1 should be converted to #include includename2 null includefile tells LINT to ignore all #include directives that attempt to include the specified file. search pathname is equivalent to Include=pathname on the LINT command line. November, 1995 Page 33 LINT Reference Manual Thinkage Ltd. system_search pathname is equivalent to StandardInclude=pathname on the LINT command line. _I_n_s_t_a_l_l_a_t_i_o_n_ _F_i_l_e_s_: An installation file specifies the pathnames for software and data files used by LINT. Installation files are text files made up of comment lines and option lines. Comment lines: Any line whose first non-blank character is # will be taken as a comment. Blank lines are also considered comments. Option lines: Option lines have the format Keyword=pathname In this documentation, keywords are written with some letters in upper case and some in lower case. You may abbreviate keywords by omitting any or all of the letters shown in lower case. The remaining letters may be entered in either upper or lower case; the documentation simply uses upper case to show which characters may not be omitted. In this version of LINT, possible option lines are: Include=pathname gives the directory containing the LINT include files. Library=pathname gives the directory containing the LINT libraries. Program=pathname gives the directory containing the LINT executable files (CPP, and so on). Page 34 November, 1995