Dec 182017
 
A text file with some "rules" for writing good C code.
File CRULES.ZIP from The Programmer’s Corner in
Category C Source Code
A text file with some “rules” for writing good C code.
File Name File Size Zip Size Zip Type
CRULES.DOC 7544 3333 deflated

Download File CRULES.ZIP Here

Contents of the CRULES.DOC file



NOTES FROM THE ULTRA-CONSERVATIVE RIGHT WING


Here's a list of rules that every C programmer should follow.
Occasionally, a rule may be violated, but only for a really good
reason.

1. Most standard functions have a header associated with them,
which should always be included. The manuals often fail to
identify what this header is, although it's there in
"/usr/include" (or wherever). You might consider grepping the
header files to discover what headers go with what functions.
This rule means that most C files will start with 5 to 10
includes. Don't feel weird if some of your files start with even
more.

2. Never declare a function if it's declared in a header, as
redundant declarations lessen reliability, portability, and
maintainability. If you discover that some standard functions
aren't in any header, you might consider coding a header so you
can just include it all the time.

3. Always declare the return value of a function when the
function is defined, even if it's "int". This makes your intent
clear. It also avoids letting a function default to "int" when
it should have been declared "void".

4. For functions internal to a file (and, therefore, not declared
in a header), order them so that redundant declarations aren't
necessary. That is, order them as a Pascal program would be,
with "main" at the end. Only in the case of mutual recursion is
this impossible.

5. Always call "exit(0)" at the end of "main".

6. Make all variables and functions "static", unless they are
external to the file. This helps the reader by indicating the
locality of the object, and it also avoids name clashes in the
linker.

7. Don't use "int", "0", and "1" for Boolean operations, as these
are needlessly general. Instead, use these:

typedef int BOOLEAN;
#define FALSE 0
#define TRUE 1

8. Where a logical expression is required ("if", "while", etc.),
do not write an integer expression. That is, do this:

if (*p != '\0')


not this:

if (*p)

This is done to speed up debugging. When the second technique is
used, mistakes are often made because the negation of the correct
expression is accidentally written. This bug is perhaps most
frequent with non-intuitive return values, such as the one from
"strcmp".

9. Never call a function without checking its error return. If
the error is impossible, at least call "assert", as in this
example:

if (close(fd) == -1)
assert(FALSE);

10. Check null pointers against NULL, never against 0 or anything
else. Do not cast NULL:

if (flurb(x, y) == (struct Rcd *)NULL) /* bad */
...

11. When you have an initialization, a test, and an
incrementation, use a "for" loop instead of a "while" loop. This
makes the loop control more explicit and reduces the possibility
of forgetting to increment.

12. When calling a function that returns a useful value or an
error return, use this "assign and check" paradigm:


if ((p = fcn(x, y)) == NULL)
... handle error ...

While ordinarily I would recommend against doing assignment in
the middle of an expression, this is an exception. It occurs so
often that it's immediately recognizable to the experienced
reader, requiring no time to figure out. Non-experienced readers
should learn about it.

13. Never read anything from a human user without checking it
thoroughly for errors and reporting problems back precisely. For
example, if the user hits Control-D or Control-Z, don't give a
"conversion error" message. This rule prohibits the use of "scanf"
in most cases.

14. Don't use lousy functions just because they're in the
library. What some library contributors know about programming
you could fit in your left ear. This rules out functions like
"atol", which reports no error.

15. Do not put in gratuitous comments, because it cheapens the
value of all comments. Then the reader gets into the habit of
skipping comments, and, when you have something important to
communicate, there's no way to do it. Also, comments make the
code harder to scan, so they have to be really useful for the
reader to want to pay the price.

Here's an example. First, a gratuitous comment:

/* get input from tape drive */
if (readtape() == ERROR)
...

Now, a useful comment:

/* can't use gettape() -- hangs system when buffered */
if (readtape() == ERROR)
...

16. Except for the numbers -1, 0, and, maybe, 1, always use a
symbolic constant. Do not dimension arrays with numbers like 81,
257, etc. For string lengths, adopt a convention and stick with
it. I use a symbolic constant to define the length exclusive of
the NUL byte, and then add one for dimensioning. The alternative
is, of course, also OK.

17. Every "switch" statement should have a "default" case, to
reduce debugging. If it can't ever occur, use "assert":

switch (x) {
...
default:
assert(FALSE);
}

18. If your compiler supports function prototypes, always use
them, both for library functions and for your own. They are the
greatest contribution to C programming since the curly brace.
I've found this paradigm useful for static functions, as it makes
modifications easier:

static BOOLEAN fcn(int, float);
static BOOLEAN fcn(count, val)
int count;
float val;
{
...
}

Note that come compilers are set up to ignore library prototypes
by default. For example, with Microsoft C you have to define the
symbol "LINT_ARGS".

19. Find out what compiler options generate the most warnings and
the strictest error checking, and turn them on. Make sure all of
your files compile with no warnings at all, or else you'll miss a
new warning because it's mixed in with the old ones. Doing this
will often mean that you'll use lots of casts. But don't just
blindly put in a cast to make a warning go away, or you might
overlook an actual bug.

20. How you lay out your programs is a matter of personal
preference. But at least be consistent, or you risk telling the
reader that you don't know what you're doing. Either put a
statement on the same line as the "if", or on the next line, but
don't do it sometimes one way and sometimes the other. Put
blanks between a function name and the left parenthesis, or don't,
but always do it the same way. Since all bugs are introduced
during text editing, that's when you need a consistent style.
So, don't use a C beautifier, unless it's to fix up a program
someone else gave you.

21. Call "assert" as often as you have the energy to. Don't
define "NDEBUG" to remove assertions when your program is ready for
delivery, because that's when undiscovered bugs have their worst
consequences. Remove assertions only when the profiler tells you
that you must.


Marc J. Rochkind
February 7, 1987
CompuServe 75765,1233

Copyright 1987 Advanced Programming Institute, Ltd. May be freely
reproduced and distributed, but only in its entirety, with no
editing whatsoever, except that misspellings may have the marking
"[sic]" inserted after them, like thas [sic]. The author's name and
this Copyright notice must be included.



 December 18, 2017  Add comments

Leave a Reply