C Coding Standards

Contents

Introduction

The source code for programming projects should always be organized and written with the future tasks of testing, debugging and maintenance (possibly by others) in mind. These tasks will be easier if the project is well organized and the source code is written in a clear and consistent manner.

This document describes some basic rules for C coding and project organization. Some general aspects of the portability problem are also addressed.

Recommended Organizational and Coding Standards

Organization:
Each project has a separate directory. For example,

Each project directory must have README and Makefile files. The README file should give a general overview of the project and the files that implement it. It should provide the information about author, the short description of the project and list of all files belonging to the project.

Documentation-I (public):
The ''public'' documentation of your source code should inform a reader of who wrote the code and describe what it does and how to use the interfaces described. The public comments should provide sufficient information for a reader to use the functions without having to read the actual C code that implements the functions. We strongly recommend that you write these public comments before you write your code. (to focuss your mind on what you really want the function to do.)

All source code files (*.c and *.h) should conform to the following general commenting standards:

Notes

You may noticed that the convention used for the public comments, specifically the /** (with the extra *) and the tags @param and @return, correspond to Java commenting standards. In particular javadoc can parse these specially formatted comments and the following declaration to produce nicely formatted HTML documentation automatically. While there is no version of javadoc for C code at this time, it does no harm to use the clear convention of Java in your C code1.

Documentation-II (private):

While the public documentation should be written so that it does not require the reader to understand or even look at the implementation, private documentation is meant to help the reader understand the actual C code implementing a function. The comments should be written under the assumption that the reader is a competent C programmer. For example:

             i++;  /* Increment i by one */
is a useless comment since it is entirely obvious to a C programmer.

Often, no private comments are required at all in well written programs. The use of descriptive variable and function names is also a great help. Using descriptive names often eliminates the need for comments (private) Consider:

      foo = foo->bar;  /* move "foo" to next item */

The comment would be unnecessary with the more intelligent variable and field names:

     item = item->next;

Avoid ``magic numbers'':
Numbers should rarely be placed directly in the source code. (Common exceptions are the numbers 0 (zero), 1 or -1.) Instead use an enum data type or the #define preprocessor directive. (It is usually preferable to use an enum for a small number of integers instead of a #define.)

For example, do not write code like:

   double x = 3.14159265358979323846*2.6*2.6;

or

   for(i = 32; i < 212; i += 2)

or

   if ((j = foo()) == 2)

instead, use:

   #include <math.h>  /* This defines the value of PI */
   #define RADIUS 2.6
   double x = M_PI*RADIUS*RADIUS;

or

   /* Note following temperatures assume Farenheit scale */
   #define FREEZING 32
   #define BOILING 212
   #define TEMP_INCREMENT 2
   for(i = FREEZING; i < BOILING; i += TEMP_INCREMENT)

or

   typedef enum {FooGood = 0,
                 FooWarn = 1,
                 FooBad = 2} FooReturn_t;
   if ((j = foo()) == FooBad)

Compile with all warnings turned on (we will do so!):
You should compile C source code will all warnings turned on. Your C code should produce no warnings.

Portability
Try to use only POSIX/ANSI compatible library functions.

No gotos
You can use all of the ANSI C language except for the goto statement.

Header files:
Header files should only contain declarations (such as typedefs or function prototypes) and preprocessor directives (such as constants and macros). Executable C code (such as a function body) should never be placed in a header file.

.h protection
All .h files must be protected so that they are never included more than once and that the order of their inclusion is less critical. For example, the header file foo.h should be structured as:

#ifndef FOO_H
#define FOO_H
 
/* Body of foo.h with (possibly) other #includes...  */
 
#endif /* FOO_H */
Line length and avoiding TABS:
No source code line should be longer than 80 characters. Use spaces, not tabs, for indentation. (some editors changes it in an automatic way)

Other C programming conventions

Using asserts

Asserts should not be used as a way of informing end-users of predictable error conditions in the operation of a program. Rather, they should be used mainly during the development stage to help the programmer figure out where things are going wrong.

Despite this, the source code often uses asserts in this ``lazy'' way.

Incorrect conventions

There is one coding ``standard'' that is commonly used but is incorrect and may lead to portability problems. In particular, there are occasions where the following assumptions are made:

1.
A generic pointer void * is the same size as an integer (int ) and data of one type can be cast to the other.

2.
A generic pointer void * and a pointer to a function void *()(...) are the same size and either can be cast to the other.

Both of these assumptions violate the formal specifications in the ANSI C standard. They are, however, very commonly encountered.

Using these convention makes some of the code easier to write and more readable. Note that there is NO assumption about the size of these things. Normally, however, they are all either 16 or 32 bits.

Some of the problems explore ways to avoid these assumptions.

Miscellaneous conventions

Some of the source code follows some other arbitrary conventions that are a matter of personal choice. These include:

Addresses of functions:
If funcP is a function pointer data type and foo() is a function, you can use funcP = &foo to set funcP to be a pointer to the function foo(). Other programmers can use the shorter and equivalent form: funcP = foo .

Underscores for private names:
When a name (such as a typedef or a private variable is used in a module, I usually prepend an underscore character (`_') to its ``logical'' name.