Annotation of 43BSDReno/share/doc/ps1/09.lint/lint.ms, revision 1.1

1.1     ! root        1: .\"    @(#)lint        6.1 (Berkeley) 5/7/86
        !             2: .\"
        !             3: .EH 'PS1:9-%''Lint, a C Program Checker'
        !             4: .OH 'Lint, a C Program Checker''PS1:9-%'
        !             5: .\".RP
        !             6: .ND "July 26, 1978"
        !             7: .OK
        !             8: .\"Program Portability
        !             9: .\"Strong Type Checking
        !            10: .TL
        !            11: Lint, a C Program Checker
        !            12: .AU "MH 2C-559" 3968
        !            13: S. C. Johnson
        !            14: .AI
        !            15: .MH
        !            16: .AB
        !            17: .PP
        !            18: .I Lint
        !            19: is a command which examines C source programs,
        !            20: detecting
        !            21: a number of bugs and obscurities.
        !            22: It enforces the type rules of C more strictly than
        !            23: the C compilers.
        !            24: It may also be used to enforce a number of portability
        !            25: restrictions involved in moving
        !            26: programs between different machines and/or operating systems.
        !            27: Another option detects a number of wasteful, or error prone, constructions
        !            28: which nevertheless are, strictly speaking, legal.
        !            29: .PP
        !            30: .I Lint
        !            31: accepts multiple input files and library specifications, and checks them for consistency.
        !            32: .PP
        !            33: The separation of function between
        !            34: .I lint
        !            35: and the C compilers has both historical and practical
        !            36: rationale.
        !            37: The compilers turn C programs into executable files rapidly
        !            38: and efficiently.
        !            39: This is possible in part because the
        !            40: compilers do not do sophisticated
        !            41: type checking, especially between
        !            42: separately compiled programs.
        !            43: .I Lint
        !            44: takes a more global, leisurely view of the program,
        !            45: looking much more carefully at the compatibilities.
        !            46: .PP
        !            47: This document discusses the use of
        !            48: .I lint ,
        !            49: gives an overview of the implementation, and gives some hints on the
        !            50: writing of machine independent C code.
        !            51: .AE
        !            52: .CS 10 2 12 0 0 5
        !            53: .SH
        !            54: Introduction and Usage
        !            55: .PP
        !            56: Suppose there are two C
        !            57: .[
        !            58: Kernighan Ritchie Programming Prentice 1978
        !            59: .]
        !            60: source files,
        !            61: .I file1. c
        !            62: and
        !            63: .I file2.c  ,
        !            64: which are ordinarily compiled and loaded together.
        !            65: Then the command
        !            66: .DS
        !            67: lint  file1.c  file2.c
        !            68: .DE
        !            69: produces messages describing inconsistencies and inefficiencies
        !            70: in the programs.
        !            71: The program enforces the typing rules of C
        !            72: more strictly than the C compilers
        !            73: (for both historical and practical reasons)
        !            74: enforce them.
        !            75: The command
        !            76: .DS
        !            77: lint  \-p  file1.c  file2.c
        !            78: .DE
        !            79: will produce, in addition to the above messages, additional messages
        !            80: which relate to the portability of the programs to other operating
        !            81: systems and machines.
        !            82: Replacing the
        !            83: .B \-p
        !            84: by
        !            85: .B \-h
        !            86: will produce messages about various error-prone or wasteful constructions
        !            87: which, strictly speaking, are not bugs.
        !            88: Saying
        !            89: .B \-hp
        !            90: gets the whole works.
        !            91: .PP
        !            92: The next several sections describe the major messages;
        !            93: the document closes with sections
        !            94: discussing the implementation and giving suggestions
        !            95: for writing portable C.
        !            96: An appendix gives a summary of the
        !            97: .I lint
        !            98: options.
        !            99: .SH
        !           100: A Word About Philosophy
        !           101: .PP
        !           102: Many of the facts which
        !           103: .I lint
        !           104: needs may be impossible to
        !           105: discover.
        !           106: For example, whether a given function in a program ever gets called
        !           107: may depend on the input data.
        !           108: Deciding whether
        !           109: .I exit
        !           110: is ever called is equivalent to solving the famous ``halting problem,'' known to be
        !           111: recursively undecidable.
        !           112: .PP
        !           113: Thus, most of the
        !           114: .I lint
        !           115: algorithms are a compromise.
        !           116: If a function is never mentioned, it can never be called.
        !           117: If a function is mentioned,
        !           118: .I lint
        !           119: assumes it can be called; this is not necessarily so, but in practice is quite reasonable.
        !           120: .PP
        !           121: .I Lint
        !           122: tries to give information with a high degree of relevance.
        !           123: Messages of the form ``\fIxxx\fR might be a bug''
        !           124: are easy to generate, but are acceptable only in proportion
        !           125: to the fraction of real bugs they uncover.
        !           126: If this fraction of real bugs is too small, the messages lose their credibility
        !           127: and serve merely to clutter up the output,
        !           128: obscuring the more important messages.
        !           129: .PP
        !           130: Keeping these issues in mind, we now consider in more detail
        !           131: the classes of messages which
        !           132: .I lint
        !           133: produces.
        !           134: .SH
        !           135: Unused Variables and Functions
        !           136: .PP
        !           137: As sets of programs evolve and develop,
        !           138: previously used variables and arguments to
        !           139: functions may become unused;
        !           140: it is not uncommon for external variables, or even entire
        !           141: functions, to become unnecessary, and yet
        !           142: not be removed from the source.
        !           143: These ``errors of commission'' rarely cause working programs to fail, but they are a source
        !           144: of inefficiency, and make programs harder to understand
        !           145: and change.
        !           146: Moreover, information about such unused variables and functions can occasionally
        !           147: serve to discover bugs; if a function does a necessary job, and
        !           148: is never called, something is wrong!
        !           149: .PP
        !           150: .I Lint
        !           151: complains about variables and functions which are defined but not otherwise
        !           152: mentioned.
        !           153: An exception is variables which are declared through explicit
        !           154: .B extern
        !           155: statements but are never referenced; thus the statement
        !           156: .DS
        !           157: extern  float  sin(\|);
        !           158: .DE
        !           159: will evoke no comment if
        !           160: .I sin
        !           161: is never used.
        !           162: Note that this agrees with the semantics of the C compiler.
        !           163: In some cases, these unused external declarations might be of some interest; they
        !           164: can be discovered by adding the
        !           165: .B \-x
        !           166: flag to the
        !           167: .I lint
        !           168: invocation.
        !           169: .PP
        !           170: Certain styles of programming
        !           171: require many functions to be written with similar interfaces;
        !           172: frequently, some of the arguments may be unused
        !           173: in many of the calls.
        !           174: The
        !           175: .B \-v
        !           176: option is available to suppress the printing of
        !           177: complaints about unused arguments.
        !           178: When
        !           179: .B \-v
        !           180: is in effect, no messages are produced about unused
        !           181: arguments except for those
        !           182: arguments which are unused and also declared as
        !           183: register arguments; this can be considered
        !           184: an active (and preventable) waste of the register
        !           185: resources of the machine.
        !           186: .PP
        !           187: There is one case where information about unused, or
        !           188: undefined, variables is more distracting
        !           189: than helpful.
        !           190: This is when
        !           191: .I lint
        !           192: is applied to some, but not all, files out of a collection
        !           193: which are to be loaded together.
        !           194: In this case, many of the functions and variables defined
        !           195: may not be used, and, conversely,
        !           196: many functions and variables defined elsewhere may be used.
        !           197: The
        !           198: .B \-u
        !           199: flag may be used to suppress the spurious messages which might otherwise appear.
        !           200: .SH
        !           201: Set/Used Information
        !           202: .PP
        !           203: .I Lint
        !           204: attempts to detect cases where a variable is used before it is set.
        !           205: This is very difficult to do well;
        !           206: many algorithms take a good deal of time and space,
        !           207: and still produce messages about perfectly valid programs.
        !           208: .I Lint
        !           209: detects local variables (automatic and register storage classes)
        !           210: whose first use appears physically earlier in the input file than the first assignment to the variable.
        !           211: It assumes that taking the address of a variable constitutes a ``use,'' since the actual use
        !           212: may occur at any later time, in a data dependent fashion.
        !           213: .PP
        !           214: The restriction to the physical appearance of variables in the file makes the
        !           215: algorithm very simple and quick to implement,
        !           216: since the true flow of control need not be discovered.
        !           217: It does mean that
        !           218: .I lint
        !           219: can complain about some programs which are legal,
        !           220: but these programs would probably be considered bad on stylistic grounds (e.g. might
        !           221: contain at least two \fBgoto\fR's).
        !           222: Because static and external variables are initialized to 0,
        !           223: no meaningful information can be discovered about their uses.
        !           224: The algorithm deals correctly, however, with initialized automatic variables, and variables
        !           225: which are used in the expression which first sets them.
        !           226: .PP
        !           227: The set/used information also permits recognition of those local variables which are set
        !           228: and never used; these form a frequent source of inefficiencies, and may also be symptomatic of bugs.
        !           229: .SH
        !           230: Flow of Control
        !           231: .PP
        !           232: .I Lint
        !           233: attempts to detect unreachable portions of the programs which it processes.
        !           234: It will complain about unlabeled statements immediately following
        !           235: \fBgoto\fR, \fBbreak\fR, \fBcontinue\fR, or \fBreturn\fR statements.
        !           236: An attempt is made to detect loops which can never be left at the bottom, detecting the
        !           237: special cases
        !           238: \fBwhile\fR( 1 ) and \fBfor\fR(;;) as infinite loops.
        !           239: .I Lint
        !           240: also complains about loops which cannot be entered at the top;
        !           241: some valid programs may have such loops, but at best they are bad style,
        !           242: at worst bugs.
        !           243: .PP
        !           244: .I Lint
        !           245: has an important area of blindness in the flow of control algorithm:
        !           246: it has no way of detecting functions which are called and never return.
        !           247: Thus, a call to
        !           248: .I exit
        !           249: may cause unreachable code which
        !           250: .I lint
        !           251: does not detect; the most serious effects of this are in the
        !           252: determination of returned function values (see the next section).
        !           253: .PP
        !           254: One form of unreachable statement is not usually complained about by
        !           255: .I lint;
        !           256: a
        !           257: .B break
        !           258: statement that cannot be reached causes no message.
        !           259: Programs generated by
        !           260: .I yacc ,
        !           261: .[
        !           262: Johnson Yacc 1975
        !           263: .]
        !           264: and especially
        !           265: .I lex ,
        !           266: .[
        !           267: Lesk Lex
        !           268: .]
        !           269: may have literally hundreds of unreachable
        !           270: .B break
        !           271: statements.
        !           272: The
        !           273: .B \-O
        !           274: flag in the C compiler will often eliminate the resulting object code inefficiency.
        !           275: Thus, these unreached statements are of little importance,
        !           276: there is typically nothing the user can do about them, and the
        !           277: resulting messages would clutter up the
        !           278: .I lint
        !           279: output.
        !           280: If these messages are desired,
        !           281: .I lint
        !           282: can be invoked with the
        !           283: .B \-b
        !           284: option.
        !           285: .SH
        !           286: Function Values
        !           287: .PP
        !           288: Sometimes functions return values which are never used;
        !           289: sometimes programs incorrectly use function ``values''
        !           290: which have never been returned.
        !           291: .I Lint
        !           292: addresses this problem in a number of ways.
        !           293: .PP
        !           294: Locally, within a function definition,
        !           295: the appearance of both
        !           296: .DS
        !           297: return(  \fIexpr\fR  );
        !           298: .DE
        !           299: and
        !           300: .DS
        !           301: return ;
        !           302: .DE
        !           303: statements is cause for alarm;
        !           304: .I lint
        !           305: will give the message
        !           306: .DS
        !           307: function \fIname\fR contains return(e) and return
        !           308: .DE
        !           309: The most serious difficulty with this is detecting when a function return is implied
        !           310: by flow of control reaching the end of the function.
        !           311: This can be seen with a simple example:
        !           312: .DS
        !           313: .ta .5i 1i 1.5i
        !           314: \fRf ( a ) {
        !           315:        if ( a ) return ( 3 );
        !           316:        g (\|);
        !           317:        }
        !           318: .DE
        !           319: Notice that, if \fIa\fR tests false, \fIf\fR will call \fIg\fR and then return
        !           320: with no defined return value; this will trigger a complaint from
        !           321: .I lint .
        !           322: If \fIg\fR, like \fIexit\fR, never returns,
        !           323: the message will still be produced when in fact nothing is wrong.
        !           324: .PP
        !           325: In practice, some potentially serious bugs have been discovered by this feature;
        !           326: it also accounts for a substantial fraction of the ``noise'' messages produced
        !           327: by
        !           328: .I lint .
        !           329: .PP
        !           330: On a global scale,
        !           331: .I lint
        !           332: detects cases where a function returns a value, but this value is sometimes,
        !           333: or always, unused.
        !           334: When the value is always unused, it may constitute an inefficiency in the function definition.
        !           335: When the value is sometimes unused, it may represent bad style (e.g., not testing for
        !           336: error conditions).
        !           337: .PP
        !           338: The dual problem, using a function value when the function does not return one,
        !           339: is also detected.
        !           340: This is a serious problem.
        !           341: Amazingly, this bug has been observed on a couple of occasions
        !           342: in ``working'' programs; the desired function value just happened to have been computed
        !           343: in the function return register!
        !           344: .SH
        !           345: Type Checking
        !           346: .PP
        !           347: .I Lint
        !           348: enforces the type checking rules of C more strictly than the compilers do.
        !           349: The additional checking is in four major areas:
        !           350: across certain binary operators and implied assignments,
        !           351: at the structure selection operators,
        !           352: between the definition and uses of functions,
        !           353: and in the use of enumerations.
        !           354: .PP
        !           355: There are a number of operators which have an implied balancing between types of the operands.
        !           356: The assignment, conditional ( ?\|: ), and relational operators
        !           357: have this property; the argument
        !           358: of a \fBreturn\fR statement,
        !           359: and expressions used in initialization also suffer similar conversions.
        !           360: In these operations,
        !           361: \fBchar\fR, \fBshort\fR, \fBint\fR, \fBlong\fR, \fBunsigned\fR, \fBfloat\fR, and \fBdouble\fR types may be freely intermixed.
        !           362: The types of pointers must agree exactly,
        !           363: except that arrays of \fIx\fR's can, of course, be intermixed with pointers to \fIx\fR's.
        !           364: .PP
        !           365: The type checking rules also require that, in structure references, the
        !           366: left operand of the \(em> be a pointer to structure, the left operand of the \fB.\fR
        !           367: be a structure, and the right operand of these operators be a member
        !           368: of the structure implied by the left operand.
        !           369: Similar checking is done for references to unions.
        !           370: .PP
        !           371: Strict rules apply to function argument and return value
        !           372: matching.
        !           373: The types \fBfloat\fR and \fBdouble\fR may be freely matched,
        !           374: as may the types \fBchar\fR, \fBshort\fR, \fBint\fR, and \fBunsigned\fR.
        !           375: Also, pointers can be matched with the associated arrays.
        !           376: Aside from this, all actual arguments must agree in type with their declared counterparts.
        !           377: .PP
        !           378: With enumerations, checks are made that enumeration variables or members are not mixed
        !           379: with other types, or other enumerations,
        !           380: and that the only operations applied are =, initialization, ==, !=, and function arguments and return values.
        !           381: .SH
        !           382: Type Casts
        !           383: .PP
        !           384: The type cast feature in C was introduced largely as an aid
        !           385: to producing more portable programs.
        !           386: Consider the assignment
        !           387: .DS
        !           388: p = 1 ;
        !           389: .DE
        !           390: where
        !           391: .I p
        !           392: is a character pointer.
        !           393: .I Lint
        !           394: will quite rightly complain.
        !           395: Now, consider the assignment
        !           396: .DS
        !           397: p = (char \(**)1 ;
        !           398: .DE
        !           399: in which a cast has been used to
        !           400: convert the integer to a character pointer.
        !           401: The programmer obviously had a strong motivation
        !           402: for doing this, and has clearly signaled his intentions.
        !           403: It seems harsh for
        !           404: .I lint
        !           405: to continue to complain about this.
        !           406: On the other hand, if this code is moved to another
        !           407: machine, such code should be looked at carefully.
        !           408: The
        !           409: .B \-c
        !           410: flag controls the printing of comments about casts.
        !           411: When
        !           412: .B \-c
        !           413: is in effect, casts are treated as though they were assignments
        !           414: subject to complaint; otherwise, all legal casts are passed without comment,
        !           415: no matter how strange the type mixing seems to be.
        !           416: .SH
        !           417: Nonportable Character Use
        !           418: .PP
        !           419: On the PDP-11, characters are signed quantities, with a range
        !           420: from \-128 to 127.
        !           421: On most of the other C implementations, characters take on only positive
        !           422: values.
        !           423: Thus,
        !           424: .I lint
        !           425: will flag certain comparisons and assignments as being
        !           426: illegal or nonportable.
        !           427: For example, the fragment
        !           428: .DS
        !           429: char c;
        !           430:        ...
        !           431: if( (c = getchar(\|)) < 0 ) ....
        !           432: .DE
        !           433: works on the PDP-11, but
        !           434: will fail on machines where characters always take
        !           435: on positive values.
        !           436: The real solution is to declare
        !           437: .I c
        !           438: an integer, since
        !           439: .I getchar
        !           440: is actually returning
        !           441: integer values.
        !           442: In any case,
        !           443: .I lint
        !           444: will say
        !           445: ``nonportable character comparison''.
        !           446: .PP
        !           447: A similar issue arises with bitfields; when assignments
        !           448: of constant values are made to bitfields, the field may
        !           449: be too small to hold the value.
        !           450: This is especially true because
        !           451: on some machines bitfields are considered as signed
        !           452: quantities.
        !           453: While it may seem unintuitive to consider
        !           454: that a two bit field declared of type
        !           455: .B int
        !           456: cannot hold the value 3, the problem disappears
        !           457: if the bitfield is declared to have type
        !           458: .B unsigned .
        !           459: .SH
        !           460: Assignments of longs to ints
        !           461: .PP
        !           462: Bugs may arise from the assignment of
        !           463: .B long
        !           464: to
        !           465: an
        !           466: .B int ,
        !           467: which loses accuracy.
        !           468: This may happen in programs
        !           469: which have been incompletely converted to use
        !           470: .B typedefs .
        !           471: When a
        !           472: .B typedef
        !           473: variable
        !           474: is changed from \fBint\fR to \fBlong\fR,
        !           475: the program can stop working because
        !           476: some intermediate results may be assigned
        !           477: to \fBints\fR, losing accuracy.
        !           478: Since there are a number of legitimate reasons for
        !           479: assigning \fBlongs\fR to \fBints\fR, the detection
        !           480: of these assignments is enabled
        !           481: by the
        !           482: .B \-a
        !           483: flag.
        !           484: .SH
        !           485: Strange Constructions
        !           486: .PP
        !           487: Several perfectly legal, but somewhat strange, constructions
        !           488: are flagged by
        !           489: .I lint;
        !           490: the messages hopefully encourage better code quality, clearer style, and
        !           491: may even point out bugs.
        !           492: The
        !           493: .B \-h
        !           494: flag is used to enable these checks.
        !           495: For example, in the statement
        !           496: .DS
        !           497: \(**p++ ;
        !           498: .DE
        !           499: the \(** does nothing; this provokes the message ``null effect'' from
        !           500: .I lint .
        !           501: The program fragment
        !           502: .DS
        !           503: unsigned x ;
        !           504: if( x < 0 ) ...
        !           505: .DE
        !           506: is clearly somewhat strange; the
        !           507: test will never succeed.
        !           508: Similarly, the test
        !           509: .DS
        !           510: if( x > 0 ) ...
        !           511: .DE
        !           512: is equivalent to
        !           513: .DS
        !           514: if( x != 0 )
        !           515: .DE
        !           516: which may not be the intended action.
        !           517: .I Lint
        !           518: will say ``degenerate unsigned comparison'' in these cases.
        !           519: If one says
        !           520: .DS
        !           521: if( 1 != 0 ) ....
        !           522: .DE
        !           523: .I lint
        !           524: will report
        !           525: ``constant in conditional context'', since the comparison
        !           526: of 1 with 0 gives a constant result.
        !           527: .PP
        !           528: Another construction
        !           529: detected by
        !           530: .I lint
        !           531: involves
        !           532: operator precedence.
        !           533: Bugs which arise from misunderstandings about the precedence
        !           534: of operators can be accentuated by spacing and formatting,
        !           535: making such bugs extremely hard to find.
        !           536: For example, the statements
        !           537: .DS
        !           538: if( x&077 == 0 ) ...
        !           539: .DE
        !           540: or
        !           541: .DS
        !           542: x<\h'-.3m'<2 + 40
        !           543: .DE
        !           544: probably do not do what was intended.
        !           545: The best solution is to parenthesize such expressions,
        !           546: and
        !           547: .I lint
        !           548: encourages this by an appropriate message.
        !           549: .PP
        !           550: Finally, when the
        !           551: .B \-h
        !           552: flag is in force
        !           553: .I lint
        !           554: complains about variables which are redeclared in inner blocks
        !           555: in a way that conflicts with their use in outer blocks.
        !           556: This is legal, but is considered by many (including the author) to
        !           557: be bad style, usually unnecessary, and frequently a bug.
        !           558: .SH
        !           559: Ancient History
        !           560: .PP
        !           561: There are several forms of older syntax which are being officially
        !           562: discouraged.
        !           563: These fall into two classes, assignment operators and initialization.
        !           564: .PP
        !           565: The older forms of assignment operators (e.g., =+, =\-, . . . )
        !           566: could cause ambiguous expressions, such as
        !           567: .DS
        !           568: a  =\-1 ;
        !           569: .DE
        !           570: which could be taken as either
        !           571: .DS
        !           572: a =\-  1 ;
        !           573: .DE
        !           574: or
        !           575: .DS
        !           576: a  =  \-1 ;
        !           577: .DE
        !           578: The situation is especially perplexing if this
        !           579: kind of ambiguity arises as the result of a macro substitution.
        !           580: The newer, and preferred operators (+=, \-=, etc. )
        !           581: have no such ambiguities.
        !           582: To spur the abandonment of the older forms,
        !           583: .I lint
        !           584: complains about these old fashioned operators.
        !           585: .PP
        !           586: A similar issue arises with initialization.
        !           587: The older language allowed
        !           588: .DS
        !           589: int  x  \fR1 ;
        !           590: .DE
        !           591: to initialize
        !           592: .I x
        !           593: to 1.
        !           594: This also caused syntactic difficulties: for example,
        !           595: .DS
        !           596: int  x  ( \-1 ) ;
        !           597: .DE
        !           598: looks somewhat like the beginning of a function declaration:
        !           599: .DS
        !           600: int  x  ( y ) {  . . .
        !           601: .DE
        !           602: and the compiler must read a fair ways past
        !           603: .I x
        !           604: in order to sure what the declaration really is..
        !           605: Again, the problem is even more perplexing when the
        !           606: initializer involves a macro.
        !           607: The current syntax places an equals sign between the
        !           608: variable and the initializer:
        !           609: .DS
        !           610: int  x  =  \-1 ;
        !           611: .DE
        !           612: This is free of any possible syntactic ambiguity.
        !           613: .SH
        !           614: Pointer Alignment
        !           615: .PP
        !           616: Certain pointer assignments may be reasonable on some machines,
        !           617: and illegal on others, due entirely to
        !           618: alignment restrictions.
        !           619: For example, on the PDP-11, it is reasonable
        !           620: to assign integer pointers to double pointers, since
        !           621: double precision values may begin on any integer boundary.
        !           622: On the Honeywell 6000, double precision values must begin
        !           623: on even word boundaries;
        !           624: thus, not all such assignments make sense.
        !           625: .I Lint
        !           626: tries to detect cases where pointers are assigned to other
        !           627: pointers, and such alignment problems might arise.
        !           628: The message ``possible pointer alignment problem''
        !           629: results from this situation whenever either the
        !           630: .B \-p
        !           631: or
        !           632: .B \-h
        !           633: flags are in effect.
        !           634: .SH
        !           635: Multiple Uses and Side Effects
        !           636: .PP
        !           637: In complicated expressions, the best order in which to evaluate
        !           638: subexpressions may be highly machine dependent.
        !           639: For example, on machines (like the PDP-11) in which the stack
        !           640: runs backwards, function arguments will probably be best evaluated
        !           641: from right-to-left; on machines with a stack running forward,
        !           642: left-to-right seems most attractive.
        !           643: Function calls embedded as arguments of other functions
        !           644: may or may not be treated similarly to ordinary arguments.
        !           645: Similar issues arise with other operators which have side effects,
        !           646: such as the assignment operators and the increment and decrement operators.
        !           647: .PP
        !           648: In order that the efficiency of C on a particular machine not be
        !           649: unduly compromised, the C language leaves the order
        !           650: of evaluation of complicated expressions up to the
        !           651: local compiler, and, in fact, the various C compilers have considerable
        !           652: differences in the order in which they will evaluate complicated
        !           653: expressions.
        !           654: In particular, if any variable is changed by a side effect, and
        !           655: also used elsewhere in the same expression, the result is explicitly undefined.
        !           656: .PP
        !           657: .I Lint
        !           658: checks for the important special case where
        !           659: a simple scalar variable is affected.
        !           660: For example, the statement
        !           661: .DS
        !           662: \fIa\fR[\fIi\|\fR] = \fIb\fR[\fIi\fR++] ;
        !           663: .DE
        !           664: will draw the complaint:
        !           665: .DS
        !           666: warning: \fIi\fR evaluation order undefined
        !           667: .DE
        !           668: .SH
        !           669: Implementation
        !           670: .PP
        !           671: .I Lint
        !           672: consists of two programs and a driver.
        !           673: The first program is a version of the
        !           674: Portable C Compiler
        !           675: .[
        !           676: Johnson Ritchie BSTJ Portability Programs System
        !           677: .]
        !           678: .[
        !           679: Johnson portable compiler  1978
        !           680: .]
        !           681: which is the basis of the
        !           682: IBM 370, Honeywell 6000, and Interdata 8/32 C compilers.
        !           683: This compiler does lexical and syntax analysis on the input text,
        !           684: constructs and maintains symbol tables, and builds trees for expressions.
        !           685: Instead of writing an intermediate file which is passed to
        !           686: a code generator, as the other compilers
        !           687: do,
        !           688: .I lint
        !           689: produces an intermediate file which consists of lines of ascii text.
        !           690: Each line contains an external variable name,
        !           691: an encoding of the context in which it was seen (use, definition, declaration, etc.),
        !           692: a type specifier, and a source file name and line number.
        !           693: The information about variables local to a function or file
        !           694: is collected
        !           695: by accessing the symbol table, and examining the expression trees.
        !           696: .PP
        !           697: Comments about local problems are produced as detected.
        !           698: The information about external names is collected
        !           699: onto an intermediate file.
        !           700: After all the source files and library descriptions have
        !           701: been collected, the intermediate file is sorted
        !           702: to bring all information collected about a given external
        !           703: name together.
        !           704: The second, rather small, program then reads the lines
        !           705: from the intermediate file and compares all of the
        !           706: definitions, declarations, and uses for consistency.
        !           707: .PP
        !           708: The driver controls this
        !           709: process, and is also responsible for making the options available
        !           710: to both passes of
        !           711: .I lint .
        !           712: .SH
        !           713: Portability
        !           714: .PP
        !           715: C on the Honeywell and IBM systems is used, in part, to write system code for the host operating system.
        !           716: This means that the implementation of C tends to follow local conventions rather than
        !           717: adhere strictly to
        !           718: .UX
        !           719: system conventions.
        !           720: Despite these differences, many C programs have been successfully moved to GCOS and the various IBM
        !           721: installations with little effort.
        !           722: This section describes some of the differences between the implementations, and
        !           723: discusses the
        !           724: .I lint
        !           725: features which encourage portability.
        !           726: .PP
        !           727: Uninitialized external variables are treated differently in different
        !           728: implementations of C.
        !           729: Suppose two files both contain a declaration without initialization, such as
        !           730: .DS
        !           731: int a ;
        !           732: .DE
        !           733: outside of any function.
        !           734: The
        !           735: .UX
        !           736: loader will resolve these declarations, and cause only a single word of storage
        !           737: to be set aside for \fIa\fR.
        !           738: Under the GCOS and IBM implementations, this is not feasible (for various stupid reasons!)
        !           739: so each such declaration causes a word of storage to be set aside and called \fIa\fR.
        !           740: When loading or library editing takes place, this causes fatal conflicts which prevent
        !           741: the proper operation of the program.
        !           742: If
        !           743: .I lint
        !           744: is invoked with the \fB\-p\fR flag,
        !           745: it will detect such multiple definitions.
        !           746: .PP
        !           747: A related difficulty comes from the amount of information retained about external names during the
        !           748: loading process.
        !           749: On the
        !           750: .UX
        !           751: system, externally known names have seven significant characters, with the upper/lower
        !           752: case distinction kept.
        !           753: On the IBM systems, there are eight significant characters, but the case distinction
        !           754: is lost.
        !           755: On GCOS, there are only six characters, of a single case.
        !           756: This leads to situations where programs run on the
        !           757: .UX
        !           758: system, but encounter loader
        !           759: problems on the IBM or GCOS systems.
        !           760: .I Lint
        !           761: .B \-p
        !           762: causes all external symbols to be mapped to one case and truncated to six characters,
        !           763: providing a worst-case analysis.
        !           764: .PP
        !           765: A number of differences arise in the area of character handling: characters in the
        !           766: .UX
        !           767: system are eight bit ascii, while they are eight bit ebcdic on the IBM, and
        !           768: nine bit ascii on GCOS.
        !           769: Moreover, character strings go from high to low bit positions (``left to right'')
        !           770: on GCOS and IBM, and low to high (``right to left'') on the PDP-11.
        !           771: This means that code attempting to construct strings
        !           772: out of character constants, or attempting to use characters as indices
        !           773: into arrays, must be looked at with great suspicion.
        !           774: .I Lint
        !           775: is of little help here, except to flag multi-character character constants.
        !           776: .PP
        !           777: Of course, the word sizes are different!
        !           778: This causes less trouble than might be expected, at least when
        !           779: moving from the
        !           780: .UX
        !           781: system (16 bit words) to the IBM (32 bits) or GCOS (36 bits).
        !           782: The main problems are likely to arise in shifting or masking.
        !           783: C now supports a bit-field facility, which can be used to write much of
        !           784: this code in a reasonably portable way.
        !           785: Frequently, portability of such code can be enhanced by
        !           786: slight rearrangements in coding style.
        !           787: Many of the incompatibilities seem to have the flavor of writing
        !           788: .DS
        !           789: x &= 0177700 ;
        !           790: .DE
        !           791: to clear the low order six bits of \fIx\fR.
        !           792: This suffices on the PDP-11, but fails badly on GCOS and IBM.
        !           793: If the bit field feature cannot be used, the same effect can be obtained by
        !           794: writing
        !           795: .DS
        !           796: x &= \(ap 077 ;
        !           797: .DE
        !           798: which will work on all these machines.
        !           799: .PP
        !           800: The right shift operator is arithmetic shift on the PDP-11, and logical shift on most
        !           801: other machines.
        !           802: To obtain a logical shift on all machines, the left operand can be
        !           803: typed \fBunsigned\fR.
        !           804: Characters are considered signed integers on the PDP-11, and unsigned on the other machines.
        !           805: This persistence of the sign bit may be reasonably considered a bug in the PDP-11 hardware
        !           806: which has infiltrated itself into the C language.
        !           807: If there were a good way to discover the programs which would be affected, C could be changed;
        !           808: in any case,
        !           809: .I lint
        !           810: is no help here.
        !           811: .PP
        !           812: The above discussion may have made the problem of portability seem
        !           813: bigger than it in fact is.
        !           814: The issues involved here are rarely subtle or mysterious, at least to the
        !           815: implementor of the program, although they can involve some work to straighten out.
        !           816: The most serious bar to the portability of
        !           817: .UX
        !           818: system utilities has been the inability to mimic
        !           819: essential
        !           820: .UX
        !           821: system functions on the other systems.
        !           822: The inability to seek to a random character position in a text file, or to establish a pipe
        !           823: between processes, has involved far more rewriting
        !           824: and debugging than any of the differences in C compilers.
        !           825: On the other hand,
        !           826: .I lint
        !           827: has been very helpful
        !           828: in moving the
        !           829: .UX
        !           830: operating system and associated
        !           831: utility programs to other machines.
        !           832: .SH
        !           833: Shutting Lint Up
        !           834: .PP
        !           835: There are occasions when
        !           836: the programmer is smarter than
        !           837: .I lint .
        !           838: There may be valid reasons for ``illegal'' type casts,
        !           839: functions with a variable number of arguments, etc.
        !           840: Moreover, as specified above, the flow of control information
        !           841: produced by
        !           842: .I lint
        !           843: often has blind spots, causing occasional spurious
        !           844: messages about perfectly reasonable programs.
        !           845: Thus, some way of communicating with
        !           846: .I lint ,
        !           847: typically to shut it up, is desirable.
        !           848: .PP
        !           849: The form which this mechanism should take is not at all clear.
        !           850: New keywords would require current and old compilers to
        !           851: recognize these keywords, if only to ignore them.
        !           852: This has both philosophical and practical problems.
        !           853: New preprocessor syntax suffers from similar problems.
        !           854: .PP
        !           855: What was finally done was to cause a number of words
        !           856: to be recognized by
        !           857: .I lint
        !           858: when they were embedded in comments.
        !           859: This required minimal preprocessor changes;
        !           860: the preprocessor just had to agree to pass comments
        !           861: through to its output, instead of deleting them
        !           862: as had been previously done.
        !           863: Thus,
        !           864: .I lint
        !           865: directives are invisible to the compilers, and
        !           866: the effect on systems with the older preprocessors
        !           867: is merely that the
        !           868: .I lint
        !           869: directives don't work.
        !           870: .PP
        !           871: The first directive is concerned with flow of control information;
        !           872: if a particular place in the program cannot be reached,
        !           873: but this is not apparent to
        !           874: .I lint ,
        !           875: this can be asserted by the directive
        !           876: .DS
        !           877: /* NOTREACHED */
        !           878: .DE
        !           879: at the appropriate spot in the program.
        !           880: Similarly, if it is desired to turn off
        !           881: strict type checking for
        !           882: the next expression, the directive
        !           883: .DS
        !           884: /* NOSTRICT */
        !           885: .DE
        !           886: can be used; the situation reverts to the
        !           887: previous default after the next expression.
        !           888: The
        !           889: .B \-v
        !           890: flag can be turned on for one function by the directive
        !           891: .DS
        !           892: /* ARGSUSED */
        !           893: .DE
        !           894: Complaints about variable number of arguments in calls to a function
        !           895: can be turned off by the directive
        !           896: .DS
        !           897: /* VARARGS */
        !           898: .DE
        !           899: preceding the function definition.
        !           900: In some cases, it is desirable to check the
        !           901: first several arguments, and leave the later arguments unchecked.
        !           902: This can be done by following the VARARGS keyword immediately
        !           903: with a digit giving the number of arguments which should be checked; thus,
        !           904: .DS
        !           905: /* VARARGS2 */
        !           906: .DE
        !           907: will cause the first two arguments to be checked, the others unchecked.
        !           908: Finally, the directive
        !           909: .DS
        !           910: /* LINTLIBRARY */
        !           911: .DE
        !           912: at the head of a file identifies this file as
        !           913: a library declaration file; this topic is worth a
        !           914: section by itself.
        !           915: .SH
        !           916: Library Declaration Files
        !           917: .PP
        !           918: .I Lint
        !           919: accepts certain library directives, such as
        !           920: .DS
        !           921: \-ly
        !           922: .DE
        !           923: and tests the source files for compatibility with these libraries.
        !           924: This is done by accessing library description files whose
        !           925: names are constructed from the library directives.
        !           926: These files all begin with the directive
        !           927: .DS
        !           928: /* LINTLIBRARY */
        !           929: .DE
        !           930: which is followed by a series of dummy function
        !           931: definitions.
        !           932: The critical parts of these definitions
        !           933: are the declaration of the function return type,
        !           934: whether the dummy function returns a value, and
        !           935: the number and types of arguments to the function.
        !           936: The VARARGS and ARGSUSED directives can
        !           937: be used to specify features of the library functions.
        !           938: .PP
        !           939: .I Lint
        !           940: library files are processed almost exactly like ordinary
        !           941: source files.
        !           942: The only difference is that functions which are defined on a library file,
        !           943: but are not used on a source file, draw no complaints.
        !           944: .I Lint
        !           945: does not simulate a full library search algorithm,
        !           946: and complains if the source files contain a redefinition of
        !           947: a library routine (this is a feature!).
        !           948: .PP
        !           949: By default,
        !           950: .I lint
        !           951: checks the programs it is given against a standard library
        !           952: file, which contains descriptions of the programs which
        !           953: are normally loaded when
        !           954: a C program
        !           955: is run.
        !           956: When the
        !           957: .B -p
        !           958: flag is in effect, another file is checked containing
        !           959: descriptions of the standard I/O library routines
        !           960: which are expected to be portable across various machines.
        !           961: The
        !           962: .B -n
        !           963: flag can be used to suppress all library checking.
        !           964: .SH
        !           965: Bugs, etc.
        !           966: .PP
        !           967: .I Lint
        !           968: was a difficult program to write, partially
        !           969: because it is closely connected with matters of programming style,
        !           970: and partially because users usually don't notice bugs which cause
        !           971: .I lint
        !           972: to miss errors which it should have caught.
        !           973: (By contrast, if
        !           974: .I lint
        !           975: incorrectly complains about something that is correct, the
        !           976: programmer reports that immediately!)
        !           977: .PP
        !           978: A number of areas remain to be further developed.
        !           979: The checking of structures and arrays is rather inadequate;
        !           980: size
        !           981: incompatibilities go unchecked,
        !           982: and no attempt is made to match up structure and union
        !           983: declarations across files.
        !           984: Some stricter checking of the use of the
        !           985: .B typedef
        !           986: is clearly desirable, but what checking is appropriate, and how
        !           987: to carry it out, is still to be determined.
        !           988: .PP
        !           989: .I Lint
        !           990: shares the preprocessor with the C compiler.
        !           991: At some point it may be appropriate for a
        !           992: special version of the preprocessor to be constructed
        !           993: which checks for things such as unused macro definitions,
        !           994: macro arguments which have side effects which are
        !           995: not expanded at all, or are expanded more than once, etc.
        !           996: .PP
        !           997: The central problem with
        !           998: .I lint
        !           999: is the packaging of the information which it collects.
        !          1000: There are many options which
        !          1001: serve only to turn off, or slightly modify,
        !          1002: certain features.
        !          1003: There are pressures to add even more of these options.
        !          1004: .PP
        !          1005: In conclusion, it appears that the general notion of having two
        !          1006: programs is a good one.
        !          1007: The compiler concentrates on quickly and accurately turning the
        !          1008: program text into bits which can be run;
        !          1009: .I lint
        !          1010: concentrates on issues
        !          1011: of portability, style, and efficiency.
        !          1012: .I Lint
        !          1013: can afford to be wrong, since incorrectness and over-conservatism
        !          1014: are merely annoying, not fatal.
        !          1015: The compiler can be fast since it knows that
        !          1016: .I lint
        !          1017: will cover its flanks.
        !          1018: Finally, the programmer can
        !          1019: concentrate at one stage
        !          1020: of the programming process solely on the algorithms,
        !          1021: data structures, and correctness of the
        !          1022: program, and then later retrofit,
        !          1023: with the aid of
        !          1024: .I lint ,
        !          1025: the desirable properties of universality and portability.
        !          1026: .SG MH-1273-SCJ-unix
        !          1027: .\".bp
        !          1028: .[
        !          1029: $LIST$
        !          1030: .]
        !          1031: .bp
        !          1032: .SH
        !          1033: Appendix:   Current Lint Options
        !          1034: .PP
        !          1035: The command currently has the form
        !          1036: .DS
        !          1037: lint\fR [\fB\-\fRoptions ] files... library-descriptors...
        !          1038: .DE
        !          1039: The options are
        !          1040: .IP \fBh\fR
        !          1041: Perform heuristic checks
        !          1042: .IP \fBp\fR
        !          1043: Perform portability checks
        !          1044: .IP \fBv\fR
        !          1045: Don't report unused arguments
        !          1046: .IP \fBu\fR
        !          1047: Don't report unused or undefined externals
        !          1048: .IP \fBb\fR
        !          1049: Report unreachable
        !          1050: .B break
        !          1051: statements.
        !          1052: .IP \fBx\fR
        !          1053: Report unused external declarations
        !          1054: .IP \fBa\fR
        !          1055: Report assignments of
        !          1056: .B long
        !          1057: to
        !          1058: .B int
        !          1059: or shorter.
        !          1060: .IP \fBc\fR
        !          1061: Complain about questionable casts
        !          1062: .IP \fBn\fR
        !          1063: No library checking is done
        !          1064: .IP \fBs\fR
        !          1065: Same as
        !          1066: .B h
        !          1067: (for historical reasons)

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.