Dec 192017
Check cross refs and lint in C source code across several files.
File CLT162.ZIP from The Programmer’s Corner in
Category C Source Code
Check cross refs and lint in C source code across several files.
File Name File Size Zip Size Zip Type
CBCPP31.BAT 514 311 deflated
CBCPP31.CLN 822 386 deflated
CGEN.BAT 305 218 deflated
CGEN.C 694 328 deflated
CHC11.BAT 353 221 deflated
CHC11.CLN 323 196 deflated
CIC86.BAT 346 214 deflated
CIC86.CLN 659 290 deflated
CIC96.BAT 346 213 deflated
CIC96.CLN 322 220 deflated
CLINT.EXE 15877 15452 deflated
CLNT2MSG.EXE 5585 5367 deflated
CMIXC.BAT 351 219 deflated
CMIXC.CLN 344 150 deflated
CMSC70.BAT 239 181 deflated
CMSC70.C 996 348 deflated
CPARS.EXE 73446 70894 deflated
CQCWIN.BAT 245 181 deflated
CQCWIN.C 734 186 deflated
CREP.EXE 13386 13013 deflated
CSETUP.EXE 39797 39003 deflated
CSETUP.HLP 10950 3549 deflated
CSETUP.IDX 830 423 deflated
CTCPP10.BAT 250 186 deflated
CTCPP10.C 802 296 deflated
CZTC21.BAT 259 192 deflated
CZTC21.C 874 307 deflated
LICENSE.DOC 3172 1167 deflated
MVC.BAT 191 147 deflated
MVC.C 1435 429 deflated
ORDER.DOC 2327 736 deflated
README 50891 14618 deflated
SYMC.BAT 243 182 deflated
SYMC.C 1658 465 deflated
WCOM.BAT 252 192 deflated

Download File CLT162.ZIP Here

Contents of the README file


The Ultimate C Source Checking Tool

(c) 1992 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,

R&D Associates can be contacted on
COMPUSERVE by mailing user ID:

100013,1042 (USA)
100111,1162 (Europe)

NEW with version 1.62! Support for Microsoft Visual C, Watcom C386,
and Symantec C++ Pro 6.0.


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.


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.

Page - 3


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:


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:


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.)

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


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.
-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:


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


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


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:

CLINT *.C -u

Fix any errors reported before proceeding! Then you do:


And finally you add the line:


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 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


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

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


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:


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 -o report

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

Page - 9


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

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

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.



produces a usage screen summarising the options.


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"


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

and for:



-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

Page - 11


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:


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




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

'__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:


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

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.


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.


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

Page - 13



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.


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


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


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.


Turn the specified warning on.


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

Page - 15


-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.


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'

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


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


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


Page - 16


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.


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.


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


'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

-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

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


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.


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

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.

'' not used
static '' not used
'' assigned to but not used
static '' assigned to but not used
argument '' 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 '' 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.


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)

should be fully braced like this:

if (x < 5) {

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:


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 ''

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.


typedefed enum as '
typedefed struct/union as '' - use initial capital
typedefed a pointer as ''
typedefed 'unsigned char' as '' - 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.


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

'' 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

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

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:


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

 December 19, 2017  Add comments

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>