There are a number of free and commercial tools that scan your code without compiling it and warn you about errors, possible errors, and deviations from strict C coding standards. They are appropriately named static code checkers. The canonical static code checker for C, written by S.C. Johnson in the late 1970s, was called lint
. It was written mainly to check function calls, as early versions of C didn't support prototyping. lint
spawned many derivative static checkers. One such checker, written by Dave Evans of the University of Virginia's computer science department, was named lclint
and was popular on modern systems like Linux. In January 2002, Dave renamed lclint
to splint
to emphasize the increased focus on secure programming (and because splint is easier to pronounce than lclint).
The aim of splint
is to help you write the most defensive, secure, and error-free program possible. splint
, like its predecessors, can be very picky about what constitutes good code.[23] As an exercise, try to find anything in the following code that might cause a warning:
When this code is run through splint
, it warns that you're discarding the return value of scanf()
.[24]
$ splint test.c Splint 3.0.1.6 --- 11 Feb 2002 test.c: (in function main) test.c:8:2: Return value (type int) ignored: scanf("%d", &i) Result returned by function call is not used. If this is intended, can cast result to (void) to eliminate message. (Use -retvalint to inhibit warning) Finished checking --- 1 code warning
All splint
warnings have a fixed format. The first line of a splint
warning tells you the filename and function where the warning occurs. The next line gives the line number and position of the warning. After that is a description of the warning, along with instructions on how to go about suppressing this kind of warning. As you can see here, invoking splint -retvalint test.c
turns off all warnings about discarding integer function return values. Alternatively, if you don't want to turn off all reports about discarded int
return values, you can suppress the warning for just this call to scanf()
by typecasting scanf()
to void
. That is, replace scanf("%d", &i)
; with (void) scanf("%d", &i)
;. (There's yet another way to suppress this warning, by using annotations, which the interested reader can learn about from the splint
documentation.)
splint
comes with a staggering number of switches, but as you use it, you'll get a feel for which ones typically suit your needs. Many switches are Boolean in nature—they turn a feature on or off. These types of switches are preceded by a +
to turn them on or a -
to turn them off. For example, -retvalint
turns off reporting of discarded int
return values, and +retvalint
turns this reporting on (which is the default behavior).
There are two ways to use splint
. The first is informal and is used mainly when you're running splint
on someone else's code or on code that's mostly final:
$ splint +weak *.c
Without the +weak
switch, splint
is typically too picky to be useful. There are three levels of checking in addition to +weak
. You can get more details about them from the splint
manual, but they are, briefly, as follows:
+weak Weak checking, typically for unannotated C code |
+standard The default mode |
+checks Moderately strict checking |
+strict Absurdly strict checking |
The more formal use of splint
involves documenting your code specifically for use with splint
. This splint
-specific documentation is called an annotation. Annotation is a large topic, and it would take us too far afield to include it in this book, but it is well covered in the splint
documentation.
splint
supports many, but not all, of the C99 library extensions. It also doesn't support some of the C99 language changes. For instance, splint
doesn't know about complex data types or about defining an int
variable in the initializer of a for
loop.
splint
is released under the GNU GPL. Its homepage is at http://www.splint.org/.