
                                  CLINT V1.67
                                  

                      The Ultimate C Source Checking Tool

               (c) 1992-1994 R&D Associates - All Rights Reserved

          Ŀ
                                                                    
                 R&D Associates, 356 D. W. Highway Suite 232,       
                          Merrimack, NH 03054, USA                  
                                                                    
                   R&D Associates, 16 High Street, Rainham,         
                             Kent ME8 7JE, ENGLAND                  
                                                                    
          Ĵ
                                                                    
                       R&D Associates can be contacted on           
                          COMPUSERVE by mailing user ID:            
                                                                    
                               100013,1042 (USA)                    
                             100111,1162 (Europe)                   
                                                                    
          

     NEW with version 1.67! Added -Jname for include environment name, -3
     for 32 bit ints,  added new warning  messages,  added @name indirect
     command line file support, new warning messages.


                                 WHAT IS CLINT?
                                 

     CLint  is a tool which reads the  source files of your C programs, and
     generates  reports about possible problems. As  it can look at ALL the
     files  in a program, it is able to report far more than any C compiler
     can.  Use CLint while developing your  programs, and you'll be assured
     of type safe linkage, efficient code, and excellent portability.

     This  version of CLint  is released as SHAREWARE.  This means that you
     use  it on a  try-before-you-buy basis. If you  find CLint useful, you
     must  register within 30 days. We'll then send you the latest version,
     with  more  documentation,  and  you'll receive  news  of  updates and
     technical support. R&D Associates regrets that it is unable to provide
     any  support for it's shareware  products without registration. Please
     read the file LICENSE.DOC for more details.

     CLint  understands all  the industry  standard extensions  to the ANSI
     standard  such as near, far,  huge, cdecl, pascal, asm,  and so on for
     all  the supported compilers. It  understands and supports the Borland
     psuedo registers, and segment types, and the Microsoft special segment
     control extensions.

     A  special  feature  of CLint  is  that  it does  not  support models.
     Instead, all type modifiers are unique, that is:

          char *    char far *          char near *    char huge *


                                    Page - 1



     and  all variations are considered unique pointer types. The advantage
     is  that regardless  of the  model you use  for any  project, if CLint
     produces  no warnings, then  you can safely change  models with no ill
     effects.  At the same  time, it understands that  near pointers may be
     converted  to far or huge  by default. For those  of you that have had
     problems with mixed model programming, this feature alone will justify
     your purchase!

     Clint  costs just  US$35 in the  USA or Canada,  and 19 in  the UK or
     Europe.  Register today for an easier programming life. Please use the
     enclosed file ORDER.DOC.

                            **** UPDATE RECORD ****
                            

     Version  1.41  added '-x'  switch which  releases  50K more  memory to
     CLint,  but makes  checking fractionally slower.  Great for BorlandC++
     with Windows!

     Versions 1.42 - 1.44, fixed some minor bugs concerning the handling of
     prototypes  with  the 'register'  keyword,  and improved  detection of
     illegal initialisations.

     Version  1.45 fixed some previously fatal error reports when extremely
     outrageous syntax was used.

     Version  1.46 fixed 'UL' constant modifier error and a couple of minor
     I/O irritations.

     Version  1.47 fixed  upper/lower case problem  in library redefinition
     warning,  added '_asm'  and '_segname'  keywords for  MSC users, added
     '-wlib' and '-w-lib' switches to enable/disable warnings about library
     symbol redefinition.

     Version  1.50: Major  Upgrade. Replaced  SETUP.EXE with  a menu driven
     program  CSETUP.EXE which  allows CLINT.CFG  to be  edited rather than
     replaced  when  options  are  changed,  and  also  automatically edits
     AUTOEXEC.BAT  if you  allow it. Added  the ability to  be invoked from
     inside  the Borland IDE, with reports collected and usable by the IDE.
     Added   indirect  files  with   .CLN  extension,  allowing  convenient
     specification of collections of files for projects.

     Added  support for  the Intel iC96  compiler, and  other compilers for
     micro  controllers which use the syntax  'extern register' for the on-
     board I/O registers.

     Added support for Borland C++ 3.1 and it's massive runtime library.

     Added  the '-u'  switch to supress  messages when  partial programs or
     libraries are examined.

     Added  the '-T'  switch to request  that Clint  reccomend variables or
     functions which could be static.




                                    Page - 2



     Added the '-E' switch to use CLint as a full ANSI preprocessor.

     Version  1.51 -  1.52 fixed a  couple of minor  errors, fixed address,
     corrected non-ANSI handling of labels.

     Version 1.53: added support for the Intel iC86 compiler, the Microsoft
     C++ 7.0 compiler, and the Microsoft QuickC for Windows compiler. Added
     '-w-lnf'  to allow bit  fields longer than 16  bits. Major re-write of
     the manual to include all the new features.

     Version  1.54: fixed a  problem when the  last line of  a file did not
     have a line feed.

     Version 1.55: fixed a problem with #else after #elif.

     Version  1.56: Added support  for the Archimedes  68HC11 compiler, and
     the  Mix PowerC compiler. Also fixed a problem with functions taking a
     pointer-to-function  with  no  arguments. Added  support  for #message
     which has the syntax:

          #message any_string

     and   prints  the  string.  Very   useful  for  debugging  conditional
     compilations, but not supported by all compilers.

     Version  1.57:  Fixed  a  problem  with  division  by  floating  point
     constants, and constant expression evaluation.

     Version 1.58:  Fixed a  problem with  long command  option lines  from
     *.CLN files which caused improper out of memory complaints.

     Version 1.59: Fixed an internal error report with sizeof("string").

     Version 1.61:  Fixed a problem with multiple CLint libraries not being
     properly checked.

     Version 1.62:  Added  support  for  Microsoft  Visual C,  Watcom C386,
     and Symantec C++ Pro 6.0.

     Version 1.63: Fixed error when given 'f(int x,)'.

     Version 1.64: Added support for Borland C++ 4.0, made DOS Extended.

     Version 1.65: Fixed pipe problem.

     Version 1.66: Fixed initializer problem.

     Version 1.67: Added -Jname for include environment name, -3 for 32 bit
     ints,  added new warning messages,  added @name  indirect command line
     file support.







                                    Page - 3



                                  INSTALLATION
                                  

     Clint  shareware may  be downloaded  from bulletin  boards as  a self-
     extracting  archive, or  on a floppy  disk from  shareware vendors. If
     downloaded,  you must create  a directory (we  suggest C:\CLINT), copy
     the  downloaded file  there, then execute  it, then  execute CSETUP to
     complete the configuration.

     To install from a floppy insert the supplied CLint disk in a drive (we
     assume drive A: here), then type:

          A:
          CSETUP

     CSETUP  now  has an  easy to  use menu  interface. Specify  the target
     directory,  select the compiler  you're using, and  specify where your
     compiler lives. CSETUP fully supports your mouse, and has full on-line
     context sensitive help. It writes (or updates if already existing) the
     CLINT.CFG  file  according  to  your  choices,  renaming  any existing
     CLINT.CFG  file as CLINTOLD.CFG. You can  use CSETUP again at any time
     to change your choices.

     CSETUP  will automatically update your  AUTOEXEC.BAT file if required.
     You  may  refuse CSETUP  permission to  change it,  in which  case you
     should add the line:

          SET CLINT=C:\CLINT

     or similar if you installed to a different directory, and add CLint's
     directory to your path.

     If  you use a ram disk, CLint will  run faster if you tell it to place
     its  temporary files on ram disk. Assuming  you have a ram disk called
     D: then add to the following line to your AUTOEXEC.BAT file:

          SET TMP=D: (or E: etc.)
     or
          SET TEMP=D:

               WARNING:  Don't specify  a nonexistent  name here,  or CLint
               won't work!

     If  CSETUP modifies your AUTOEXEC.BAT, it  will reboot the computer to
     allow  the changes  to take effect.  If instead you  manually make the
     changes, you will need to re-boot.

               PLEASE  NOTE: If you change your  version of C you will need
               to run CSETUP again when you make the change.

     For the Shareware version only, you must complete your installation by
     executing  the batch file corresponding  to your chosen compiler. This
     will  construct in your  CLint directory the  library file required to
     check all uses of your compiler's runtime library.



                                    Page - 4



                               CONFIGURING CLINT
                               

     You  can configure CLint  to your personal  preferences by editing the
     supplied  CLINT.CFG file  which looks  like this  (varies according to
     what you told CSETUP when CLint was installed):

          # (c) R&D Associates 1992.
          # CLINT.CFG
          -IC:\TC\INCLUDE         # TurboC++ 1.0
          -lC:\CLINTREG\CTCPP10   # Clint Library for TurboC++ 1.0
          #
          # Add additional include directories with -I
          # Add your Clint library directory with -l
          # Add your common Clint warning switches:
          # -wxxx to enable warning xxx,
          # -w-xxx to disable warning xxx.
          #

     As you will see later, you can add any of CLint's options to this file
     as  you see  fit. The  '-I' line specifies  the name  of the directory
     where  your compiler's header files are  - change this as required, or
     use  CSETUP.  The  '-l'  line specifies  where  you  keep  the library
     definitions, and the name of the definition file. If you use CSETUP to
     change   your  CLint  configuration,  it  edits  your  CLINT.CFG  file
     retaining all the information that did not need to be changed.

           
           NOTE: You MUST specify complete pathnames with -I and -l!
           

     CLint  searches for  CLINT.CFG in the  current directory,  then in the
     directory  specified  in  the CLINT  environment  (SET)  variable. You
     should  set up  the standard  CLINT.CFG file  to reflect  your general
     needs.  If a special case arises in  one of your programs, simply copy
     CLINT.CFG to that directory:

          CD MYDIR
          COPY \CLINT\CLINT.CFG

     and edit it as required. No other use of CLint will be affected. CLint
     expects  that each  line in CLINT.CFG  is a CLint  option which starts
     with  '-' and is followed by an  option letter, and any required text.
     Any  number of  other lines  may be  present in  the file  and will be
     ignored. You can also comment any line by using '#' like this:

          -l\clint\cbcpp30    # BorlandC++ 3.0

     Such comments are ignored. CLint is insensitive to case in the command
     line or in CLINT.CFG except as detailed later.







                                    Page - 5



                                  USING CLINT
                                  

     In the simplest case, you will use CLint like this:

          CLINT *.C

     CLint  will read all of the  source files, analyse them carefully, and
     report on any possibly problems, ANSI violations, portability problems
     and  so forth. It assumes that all the files specified are part of one
     program,  and will  be linked together,  and linked  with the run-time
     library  routines specified in  CLINT.CFG or with  '-l' options on the
     command line.

     It  checks carefully  that symbols  declared in  one file  and used in
     another  have the same  declaration in both  files; that all functions
     defined  are actually called; that all  variables defined are used. If
     CLint  produces no  warnings or errors  about such things,  you can be
     assured that the program when linked is type-safe.

     There may be cases where you have run-time libraries supplied by other
     vendors,  or written  by yourself. You  will need to  tell CLint about
     them  to obtain full checking. If you don't, CLint will complain about
     symbols which are never defined.

     Let's assume that you have a library called MYLIB in \MYLIB, which has
     a  header MYLIB.H. The first  thing to do is  verify that there are no
     errors in MYLIB:

          CD \MYLIB
          CLINT *.C -u

     Fix any errors reported before proceeding! Then you do:

          CLINT MYLIB.H -L MYLIBDEF

     And finally you add the line:

          -l\MYLIB\MYLIBDEF

     to  CLINT.CFG. (If you  don't want to  add this line,  simply type the
     '-l' option when you run CLint.)

     The really important options you may need to use are:

          -Dname=value   define a preprocessor macro
          -Uname         undefine a preprocessor macro
          -lfile         specify a CLint library file to check against









                                    Page - 6



     When   reading  header  files,   CLint  distinguishes  between  header
     directories specified in CLINT.CFG, and those specified in the command
     line.  The former  are assumed to  be your compiler  or library header
     files, the latter header files which are part of the program.

     This  is  only  important  when '-w-shd'  is  used  (don't  warn about
     compiler headers - the default), as CLint will only be silent on minor
     problems in compiler headers - not program ones.

     The search order for headers which use "file.h" is:

          1) Current directory,

          2) Directories given in -I in the command,

          3) Directories given in -I in CLINT.CFG.

     For headers which use <file.h> only (2) and (3) are searched.

     The  built-in preprocessor is  a full ANSI  implementation. It defines
     the required preprocessor macros:

          __LINE__, __FILE_, __DATE__, __TIME__

     and also the macros

          __DOS__ and __CLINT__

     with  the value '1'. If you require __STDC__ place '-D__STDC__' on the
     command line or in CLINT.CFG.

     Some  users have encountered problems with compilers which claim to be
     ANSI, but don't have fully ANSI preprocessors. Lines like:

          #ifdef (sizeof(int) == sizeof(short))

     often  in LIMITS.H are a dead giveaway. The ANSI standard specifically
     prohibits  expressions  like this:  you can't  have casts,  sizeof, or
     enumeration  constants  in a  #if expression.  It  is usually  done by
     compilers that are trying to deduce the model you are using. Compliant
     compilers define preprocessor symbols instead.
















                                    Page - 7



                       USING CLINT FROM THE BORLAND IDE.
                       

     You  can arrange to call  CLint from inside the  Borland IDE for Turbo
     C++ 1.0 and upwards like this:

          From  the main  menu select Options,  then Transfer,  then Edit a
          blank entry entering the following information:

               Program Title:  ~CLint current file

               Program Path:  C:\CLINT\CLINT.EXE

               Command Line:  $SAVE CUR $NOSWAP $CAP MSG(CLNT2MSG) -u -x -Z
                              -D__TURBOC__ $EDNAME

          Then select Shift-F9 as the hotkey.

          Then  from the main menu select Options, then Transfer, then Edit
          a blank entry entering the following information:

               Program Title:  C~Lint PROJECT.CLN

               Program Path:  C:\CLINT\CLINT.EXE

               Command Line:  $SAVE ALL $NOSWAP $CAP MSG(CLNT2MSG) -x -Z
                              _D__TURBOC__ PROJECT.CLN

          Then select Shift-F10 as the hotkey.

     If  you installed CLint  in a different  directory, use that directory
     name instead. If you told SETUP that you're using one of the supported
     Borland  compilers, the  output filter  CLNT2MSG.EXE is  copied to the
     compiler's BIN directory. The command line options for the IDE are:

          $SAVE CUR:     save the current file

          $NOSWAP:       don't switch screens

          $CAP:          capture CLint's output

          MSG(CLNT2MSG): pipe CLint's output through the filter

          -x, -u:        standard CLint switches

          -Z:            a special CLint switch for the IDE only

          $EDNAME:       the name of the current IDE file









                                    Page - 8



     Unfortunately,  if  you have  existing project  files, you'll  need to
     enter this information for each one.

     Shift-F9  runs CLint  against the  current file.  As it  uses the '-u'
     option,  tests for  interaction with libraries  or other  files in the
     project are suppressed. It is useful for rapid checks of a file whilst
     being edited.

     To  use the second option, create  a file PROJECT.CLN for your project
     containing a line for each source file in the project. You should also
     place any project specific options using '-I', '-l', '-w' etc. one per
     line as though they were being typed on the command line (see the next
     section for details). This allows you to run CLint against your entire
     project  by typing  Shift-F10, and  when CLint  finishes the  IDE will
     correctly position the cursor against any errors or warnings detected.

     Once  you've created  PROJECT.CLN, it is  just as useful  from the DOS
     command line - just type:

          CLINT

     as the special file PROJECT.CLN is used (if it exists) when CLint is
     invoked with no file specifications. If you use MAKE, you may find it
     convenient to add a target:

          clint:
               clint -o report

     to  completely  check your  entire project,  and  leave the  report in
     'REPORT'.



























                                    Page - 9



                           THE COMMAND LINE OPTIONS.
                           

     CLint  takes a number  of source file  names, possibly with wildcards,
     and  analyses these sources. To control  the analysis and reporting, a
     number   of  options  may  occur  on  the  command  line,  or  in  the
     configuration  file CLINT.CFG, or  in files with  a '.CLN' extension -
     PROJECT.CLN is special, if no files are specified and that file exists
     it is used by default.

     The  filenames may be specified in full  or in part. Filenames with no
     extension  are assumed to have the  extension '.C', failing which they
     are  assumed to have the extension  '.CLN'. The files are inspected in
     order  of  their  occurrence  on  the  command  line.  When  wild card
     expansion occurs, the expanded names are ordered alphabetically.

     File  names with  no wildcards  and no  extension if  not matching any
     files  with the extension '.C' have the extension '.CLN' appended, and
     are then searched for in the current directory.

     Files  with the extension  '.CLN' are assumed  to contain command line
     options  and filenames, one per line.  If filenames are present in the
     file,  no wildcards  are permitted,  neither are  nested '.CLN' files.
     Such  files are supported to allow the convenient specification of the
     group of files comprising a project and the options they need. You may
     have  any number of blank lines in  the file, and you can add comments
     to any line by prefixing them with the '#' character.

     If  you use any version of the Borland IDE from Turbo C++ 1.0 upwards,
     you  should  name such  files PROJECT.CLN  as described  earlier. Such
     files  are read strictly  in left to right  order as encountered while
     reading the command line. The effect is exactly as though each line of
     the  '.CLN'  file is  inserted as  an argument  into the  command line
     replacing  the '.CLN' filename argument. In subsequent discussion, all
     comments regarding the precedence of command line options includes any
     options found in '.CLN' files too.

     All  CLint options  begin with  a leading  '-' or  '/' character  - in
     examples  below, we  use '-'. Except  as described  below, options are
     case  insensitive unless the  C standard or  operating system requires
     otherwise.

     Options  may occur in  any order on the  command line, intermixed with
     file names. The options are read in the order:

          CLINT.CFG
     and
          command line left-to-right









                                   Page - 10



     which  can  be important.  Options in  the  command line  may override
     options in CLINT.CFG or earlier options in the command line.

     
     NOTE: CLint searches for CLINT.CFG first in the current directory, and
     then  in the directory  specified in your  CLINT environment variable.
     CLint issues no warnings if CLINT.CFG can't be found.
     

     Typing:

          CLINT /?

     produces a usage screen summarising the options.
     
          -Ipath
          -ipath

     where  'path' is a directory name.  Case may be important in directory
     names  depending  on  the operating  system  you use.  It  specifies a
     directory  to search for header  files. There may be  as many of these
     options as required. The order of search for:

          #include "file"

     is

          current directory,
          -I directories given on the command line,
          -I directories given in CLINT.CFG.

     and for:

          #include <file>

     is

          -I directories given on the command line,
          -I directories given in CLINT.CFG.

     You  can force  CLint to  forget all  the -I  options in  CLINT.CFG by
     giving  '-I-' or '-i-' on the command  line prior to any other include
     paths.














                                   Page - 11



     
          -Dname
          -dname
          -Dname=value
          -dname=value

     These  options define preprocessor macros.  Although the option letter
     is  case insensitive,  the macro names  and values are  NOT. The first
     form  defines a  macro with default  replacement text  '1'. The second
     form  gives the replacement text explicitly. For your convenience, you
     may append several definitions to an option with ';' like this:

          -Dname1;name2=4;name3=5;name4

     Note that the DOS command line can't handle options like:

          -Dname="1"

     properly.

     
          -Uname

     This  option  deletes a  preprocessor  macro. It  is  not an  error to
     specify  a macro which was  not defined. It is  an error to attempt to
     undefine:

          '__TIME__', '__DATE__', '__FILE__', or '__LINE__'.

     It can be used to undefine

          '__CLINT__' or '__DOS__'

     or  any  symbols defined  in CLINT.CFG.  As with  '-D' you  can append
     several names with ';' like this:

          -Uname1;name2

     The order of '-D' and '-U' is important - you may only undefine macros
     whose definition precedes the '-U' option.

















                                   Page - 12



     
          -o file
          -O file
          -ofile
          -Ofile

     This option specifies a file to receive CLint's output. By default the
     output  is written  to 'stderr'. If  you use this  option, CLint still
     writes  the source file name it is  working on to 'stderr' to show you
     how  it is proceeding.  If more than  one of these  options occur, the
     rightmost one is used.

     
          -e0

     By  default CLint stops reading a file  if 15 errors are produced, and
     proceeds  to the next file with the  message 'Too many errors'. If you
     use this option the limit is removed.

     
          -eNNN

     Use  this option to specify  the error limit you  need. The default is
     15.  If this  option and  '-e0' occur  together, the  rightmost one is
     obeyed.
































                                   Page - 13



                                    WARNINGS
                                    

     
          -w0
          -W0

     By  default, CLint stops  reading a file if  60 warnings are produced,
     and proceeds to the next file with the message 'Too many warnings'. If
     you use this option the limit is removed.

     
          -wNNN

     Use  this option to specify the warning limit you need. The default is
     60.  If this  option and  '-w0' occur  together, the  rightmost one is
     obeyed.

     
          -wall

     A  number of CLint's  warnings are optional, and  OFF by default. This
     turns all warnings on.

     
          -w-all

     This turns all warnings off. It may usefully occur in CLINT.CFG when
     followed by '-wxxx' options to turn on only those warnings you need.

     
          -wxxx

     Turn the specified warning on.

     
          -w-xxx

     Turn the specified warning off.


















                                   Page - 14



     

     This is the complete list of warning switches. Any of them may be used
     in  CLINT.CFG or  on the  command line.  Unless changed  by CLINT.CFG,
     those switches marked below with '*' are enabled by default.

      *wcom         warn of nested comments
       webr         else needs '{'
       wfbr         for needs '{'
       wibr         if needs '{'
       wwbr         while needs '{'
       wspc         advise on spacing
       wlfb         warn of functions longer than 120 lines
       wlfbNNN      warn of functions greater than NNN lines long
       wtyb         typedefing primitive types
      *wtye         warn of typedefing enums
      *wtyg         warn of general (complex) typedefs
      *wtyp         warn of typedefing pointer types
      *wtys         warn of typedefed structs with lower case names
       wtysU        typedefed structs with names not fully in upper case
      *wstv         warn of passed/returned structs (by value)
      *wcon         warn of constant conditions
      *whdr         show warnings in user header files
       wshd         show warnings in system header files
      *wprn         warn of misuse of printf (sprintf, fprintf, etc)
      *wenu         warn of enum misuse
      *wtri         warn about trigraphs
      *winc         warn of multiply included header files
      *wiag         warn of auto aggregate initialisation
      *wunr         warn of unreachable code
      *welb         warn of empty loop bodies
      *wcil         long constant needs 'L'
      *wsig         warn of loss of significance with longs
       wsig+        warn of loss of significance with any type
      *wmxp         warn of mixed pointers to signed/unsigned char
      *wenu         warn of enum misuse
      *wnus         warn of variables defined but not used
      *wpro         warn of function use without a prototype
      *wret         warn of return misuse
      *wlib         warn of library symbol redefinition
      *wlnf         warn of bit fields longer than 16 bits
      *wreg         warn of register usage
      *wpua         warn of possibly unintended assignments
      *wbbr         warn of non-ANSI initializer bracing













                                   Page - 15



                                SPECIAL OPTIONS
                                

          -L file

     This  important option  instructs CLint  to change  it's behaviour, in
     that  it knows that the source files will be headers not program text.
     Each  prototype or external declaration in the source files is written
     to  the 'file' in  a form to be  later read into  CLint using the '-l'
     option. This file is needed if CLint is to check your usage of library
     functions and variables properly.

     Note  that many errors will  be reported if this  option is applied to
     program  source, and that the  '-L' MUST be upper  case. The file name
     case is only important if your operating system requires.

     
          -lfile

     This  option  instructs CLint  to  read a  definition  file previously
     prepared  with  the '-L'  option above  after  reading all  the source
     files. Declarations and usage in your source files will be compared to
     those recorded in the definition file, and may result in the warning:

          Warning: 'name' in file(NNN) hides a library symbol in 'file'

     If this happens, you have defined a function or variable which is also
     defined in a library. C allows this, but in some cases it may be a bug
     in  your  code.  You may  suppress  these warnings  with  the '-w-lib'
     option.

     If  you don't use the '-l' option for each library you use, CLint will
     complain  about a  long list of  functions and variables  used but not
     defined  (exactly as  the linker  would if you  failed to  link in the
     library at link time).

     The  '-l'  option is  used differently  in CLINT.CFG:  you must  use a
     directory name. For example, suppose that you place all the definition
     files you created with the '-L' option above in

          \CLINT\MYLIBS

     If you want CLint to check usage in ALIB in this directory, you place:

          -l\clint\mylibs

     in CLINT.CFG, and on the command line use:

          -lalib








                                   Page - 16



     
          -E

     Use  CLint  as  an ANSI  C  pre-processor.  The output  is  written to
     'stdout'  and may  be redirected,  or the '-o'  option may  be used to
     write  the output  to any  named file.  If wild  cards are  used, each
     source file is pre-processed in turn resulting in all output appearing
     in the same file.

     
          -u

     This  switch  informs CLint  that the  files  given are  not complete,
     either  they are  a library or  only part  of a program.  In any case,
     complaints about symbols used but not defined and defined but not used
     are suppressed.

     
          -T

     This  switch tells Clint  to detect functions  and variables which are
     only  used in the  file in which  they are declared.  It then prints a
     warning  about  all  such  variables, observing  that  they  should be
     declared 'static'.

































                                   Page - 17



                              CONTROL OF TYPEDEFS
                              

     'typedef'  is often  misused. You  can control  the way  CLint reports
     these misuses in a number of ways:

     
     -wtye enables reports of typedefing enums, for example:

          typedef enum { A, B} THING;

     provokes   the  report:  "typedefed  enum  as  'THING'".  We  consider
     typedefing  enums to be  poor practise as  discussed elsewhere, except
     for the example given below.

     
     -wtys  enables reports about  typedefing structs or  unions without an
     initial  capital letter in the name, -wtysU enables reports about this
     without  the name being all upper case.  We consider that at least the
     name should start with a capital letter, preferably all upper case.

     
     -wtyp enables reports about typedefing pointer types. We consider this
     to be one of the major abuses of typedef.

     
     -wtyg  enables reports about strange typedefs - for example typedefing
     an  array. We  produce this message  for any typedef  which is complex
     (not  a  primitive type,  struct,  union, enum,  or  pointer). Complex
     typedefs   are  in  our  opinion  dangerous  as  they  hide  too  much
     information.

     
     -wtyb  enables reports about typedefing  primitive types such as 'int'
     with names that are not all lower case. There are occasions where this
     is  useful, but  we believe that  for clarity the  typedef name should
     always be lower case.

     CLint  already knows about standard ANSI names which are typedefed, as
     follows:

          div_t, ldiv_t, size_t, wchar_t, clock_t, time_t,
          fpos_t, jmp_buf, va_list, tm,

     and will never complain about their definitions.












                                   Page - 18



                              DISCUSSION SECTIONS
                              

     We  believe that  C programs  should be  understandable, maintainable,
     portable, and above all efficient. CLint was designed to assist in the
     achievement  of these goals. CLint  produces several reports which can
     help  you write code  meeting these objectives.  We discuss several of
     the reports which may occur.

     1. EFFICIENCY
     

     
     auto aggregate initialisation

          An  'aggregate'  is  any  structure,  union  or  array  -  i.e. a
          collection  of more primitive objects.  All compilers use code to
          initialise  'auto'  objects.  Where these  objects  are primitive
          types, the code is equivalent to assignment.

          Where  the object is a 'struct', 'union', or array, the compilers
          generate  a static unnamed object of the same type and initialise
          that  - and then generate code to copy this hidden object to your
          object.

          You  can save  code and  speed up  your program  by declaring the
          object   'static'  which   avoids  the  copy   operation  as  the
          initialisation  is performed once at compile time. This will only
          work  if you never  modify the object! If  you do, then carefully
          examine  the logic of  your code - it  is almost never necessary,
          and often confusing. A common case is:

               void f()
               {
                    char string[] = "a string ....";
               }

          where  if 'string' is  not modified it should  be static. You can
          disable this warning with -w-iag.


















                                   Page - 19



     
     struct/union passed by value
     struct/union value returned

          Both  these  cases  cause  a significant  amount  of  code  to be
          generated,  and stack space  usage equivalent to  the size of the
          object.  When you  pass a  structure value,  the entire  value is
          pushed  on the stack. When you  return a structure, space for the
          return value is reserved on the stack, and in normal cases copied
          from the stack to the destination, for example:

               struct x {
                    ......
               };

               struct x f(void)
               {
                    struct x y;

                    ......
                    return y;
               }

          This  typical  code  skeleton  copies the  value  of  'y'  to the
          reserved  space on the stack, and (assuming you use the result by
          assignment)  copies that value  to the destination!  If you don't
          want these warnings, use -w-stv.

     
     '<name>' not used
     static '<name>' not used
     '<name>' assigned to but not used
     static '<name>' assigned to but not used
     argument '<name>' not used

          These  all indicate problems with the  program logic - often they
          are  a  result  of  code  changes  which  cause  previously  used
          variables  to become unused. Sometimes they indicate a real bug -
          you  assigned a value  for a reason,  but then that  value is not
          used.  However they  arise, they should  be cleared -  if only to
          reduce the size of the program.

          In  the case of "argument 'x' not used" this may be intentional -
          you can silence CLint by placing:

               #pragma argsused

          ahead of the function declaration. This clearly announces what is
          going on to any people reading the code too.








                                   Page - 20



     
     label '<name>' unused

          Most  compilers assume when they see  a label that control may be
          transferred  to  a label  by  'goto', and  therefore  discard the
          values  of any registers they may be remembering. A label that is
          not used will usually not be detected as such, and will cause the
          same  action.  This  can  result  in  larger  slower  code  being
          generated immediately following such a label.

     2. CODING STYLE
     

     
     statement after 'for' should have '{'
     statement after 'while' should have '{'
     statement after 'do' should have '{'
     statement after 'if' should have '{'
     statement after 'else' should have '{'

          Any of these not followed by a keyword, as for example:

               if (x > 5)
                    ++i;

          should be fully braced like this:

               if (x < 5) {
                    ++i;
               }

          If  you agree  with us,  any of  these may  be enabled  by -wfbr,
          -wwbr, -wibr, -webr.

     
     ' ' advised after '='
     ' ' advised after ','
     ' ' advised after ';'
     ' ' advised after ':'

          Some  spacing  styles  are  hard to  read.  We  believe  that all
          operators  should have white  space either side,  but this is too
          draconian, so we object to things like:

               a=1,b=2;f(3,a);

          which will provoke 5 complaints. It should be written as:

               a = 1, b = 2; f(3, a);

     If you want this checking, enable it with -wspc.






                                   Page - 21



     
     ' ' advised after '<keyword>'

          We  believe  that  many  people  reading  code  use  visual clues
          extensively.  One of the clues often  used is function calls have
          the  form 'name(...)'. Some  programmers have a  habit of writing
          language clauses as though they were function calls, like:

               if(j == 0)

          At  first glance, this is enough like a function call to at least
          arrest the eye. This is also enabled by -wspc.


     3. USE OF TYPEDEF.
     

     
     typedefed enum as '<name'>
     typedefed struct/union as '<name>' - use initial capital
     typedefed a pointer as '<name>'
     typedefed 'unsigned char' as '<name>' - use lower case

          We  consider typedef misuse  to be one of  the major crimes often
          committed  with  C. Some  extremely obscure  code can  occur when
          typedefs  are used, and  if the declaration is  in a header file,
          considerable  time may be needed to discover what the code really
          means - for example, given:

               #include "junk.h"

               void f()
               {
                    garbage x;

                    ........
               }

          what is 'x'? We propose some rules for the use of typedef to make
          it at least possible to get some hints:

               1) When typedefing unions or structs, always have an initial
               capital letter in the name - or capitalise the entire name.

               2) Never typedef an enumeration - use 'enum thing x' instead
               which clearly announces to the reader what is going on.

               3)  Never typedef pointer types - the presence of the '*' in
               the declaration is a valuable clue to understanding.

               4) When typedefing a primitive type, always use a lower case
               name,  the reader  can then be  assured that  all lower case
               type names are really simple objects like 'int'.




                                   Page - 22



          These  objections can  be enabled  if you  agree with  us: -wtye,
          -wtys, -wtyp, -wtyb.

     4. POTENTIALLY SERIOUS BUGS
     

     There  are many potential  bugs which CLint warns  about. Some of them
     can lead to extremely obscure problems. The most important are:

     
     '<name>' possibly used before definition

               You will recall that 'auto' and 'register' objects which are
               not  the arguments  of functions have  undefined values (for
               this  read 'whatever was on the  stack before the call'). If
               you  refer to the value of such  an object before a value is
               assigned to it you are guaranteed to get junk. Sometimes the
               message may be inappropriate, as in:

                    struct x {
                         struct x *next;
                         ......
                    } *head, *p, *q;

     >            for (p = head; p; p = q) {
                         q = p->next;
                    }

               This  provokes "'q' possibly used  before definition" at the
               line  marked with the arrow - but  we can see that 'q' is in
               fact  assigned before it's  value is required  in the 'for'.
               Almost  any other occurrence of this bug is a genuine error,
               and   it  is  worth  clearing  this  non-error  occasion  by
               initialising 'q' to NULL anyway.
     
     "evaluation order undefined"

               The standard clearly states that in a statement like:

                    int a[10], i;

                    a[i] = ++i;

               that  the meaning of the  statement is undefined because the
               compiler   writer  is   free  to   evaluate  the  expression
               components in any order that is convenient - to the compiler
               writer!  In cases like  this, he may  decide to evaluate the
               address  of the  array element  before evaluating  the right
               hand side - or he may not.








                                   Page - 23



               Similar  problems arise with  any operator which  has a side
               effect,  and CLint takes some care  to check them all. It is
               also  careful that when operators  whose evaluation order is
               defined  by the  standard are  used, ('||',  '&&', '?', ',')
               that improper complaints don't occur.

               A  particular  trap with  optimising  compilers is  that the
               order of evaluation of function arguments is undefined, so:

                    f(a[i], i++);

               provokes this complaint too.

     
     ambiguous operators need parentheses

               This occurs if any of the operators '||', '&&', '|', '&', or
               '^'  are  adjacent and  different  in an  expression without
               parentheses round one of them. For example:

                    if (flag && test1 || test2) ....

               is true if 'flag && test' or 'test2'. This occurred in CLint
               itself  - in several places! -  before we fixed it. What was
               meant was of course:

                    if (flag && (test1 || test2)) ....

               This  can cause no end of  grief, because most people forget
               the relative precedences of these operators.

     
     printf: ....

               There  are a  series of  possible errors  that can  be given
               concerning  the use  of 'printf',  'fprintf', and 'sprintf'.
               All  calls to these library functions are tested argument by
               argument   against  the  ANSI  standard  for  the  supported
               conversions.  Each  '%'  conversion is  checked  against the
               corresponding  argument to be of  the correct type. This can
               catch  a  surprising number  of  bugs in  apparently working
               programs.

               You  can also define  functions of your  own which work like
               'printf()'. You should then use the -FNname switch to inform
               CLint  of these functions  so that it can  check your use of
               these functions.










                                   Page - 24



     
     unreachable code

               This may occur due to any number of logical problems. It can
               also  be  caused by  providing  a 'return  x'  which Borland
               compilers  sometimes incorrectly  insists on  at the  end of
               functions.  In cases where you  know the statement concerned
               can't be reached, precede the offending statement with:

                    #pragma notreached

               which  will  silence  CLint, but  not  unfortunately Borland
               compilers.

     
     value should be returned
     both return and return of a value

               These  are often a hold-over from pre-ANSI C code. You would
               often write:

                    func()
                    {
                         .....
                    }

               where under ANSI you should write:

                    void func(void)
                    {
                         .....
                    }

               The second case is more worthy of attention. A number of so-
               called working programs exhibit this one - it can be a nasty
               trap.  Often,  the program  will work  - under  a particular
               compiler  - because the value in the return register left by
               a  prior expression just happened  to be the value required!
               You should always fix this.


















                                   Page - 25
