Ken Clowes (kclowes@ee.ryerson.ca)
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 fashion. In addition, the future possibility of porting the program to different environments (portability ) should be addressed at the outset.
This document describes some basic rules for C coding and project organization. Some general aspects of the portability problem are also addressed.
Many of the standards discussed here are dealt with from a more general (language-independent) way in General Coding Standards[Clo].
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.
All source code files (*.c and *.h) should conform to the following general commenting standards:
/* Copyright (C) 1999 Jane Smith (jsmith@ryerson.ca) */
/** * The functions in this file solve the classic * towers of Hanoi problem. */
/** * ``main'' manages the command line interface to solving * the towers of Hanoi problem. The command line arg * (which must be string representations of numbers) * indicate the number of disks to be moved and the source * and destination tower numbers. (The towers are * identified with the numbers 1, 2 and 3.) * * @param argc the number of command line arguments * @param argv a pointer to an array of strings where: * There must be exactly 3 arguments where: * -- the fist arg is the number of disks to move * -- the second is the ID-num of the source * -- the third is the ID-num of the destination * @return always returns an exit code of 0. */ int main(int argc, char * argv[]) {}
The conventions used for the public comments, specifically the
/**
(with the extra *
) and the tags @param
and
@return
, correspond to Java commenting standards. In
particular, a Java tool called 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 conventions of Java in your C code1.
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. Indeed, Rob Pike states:
Basically, avoid comments. If your code needs a comment to be understood, it would be better to rewrite it so it's easier to understand. Rob Pike[Pik]Using descriptive names often eliminates the need for comments, 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;
#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;
for(i = 32; i < 212; i += 2)
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;
/* Note following temperatures assume Farenheit scale */ #define FREEZING 32 #define BOILING 212 #define TEMP_INCREMENT 2 for(i = FREEZING; i < BOILING; i += TEMP_INCREMENT)
typedef enum {FooGood = 0, FooWarn = 1, FooBad = 2} FooReturn_t; if ((j = foo()) == FooBad)
#ifndef FOO_H #define FOO_H /* Body of foo.h with (possibly) other #includes... */ #endif /* FOO_H */
You may note functions such as eprintf or emalloc sprinkled through the C code. These functions come from Kernighan and Pike's[KP99, p. 109-111] utility library which we have called eprintf.o.
Their use is summarized in Table 1.
My view is that asserts should not be used as a lazy programmer's 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.
I use one coding ``standard'' that is incorrect and may lead to portability problems. In particular, there are occasions where the following assumptions are made:
void *
is the same size as an integer
(int) and data of one type can be cast to the other.
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 conventions 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.
Some of the source code follows some other arbitrary conventions that are a matter of personal choice. These include:
funcP = &foo
to set funcP to be a pointer to the
function foo(). Other programmers use the shorter and
equivalent form: funcP = foo
.
#define private static #define public
This allows me to declare things at the global level as ``private'' or ``public'' which I find closer to the semantics I have in mind.
This document was generated using the LaTeX2HTML translator Version 98.1p1 release (March 2nd, 1998)
Copyright © 1993, 1994, 1995, 1996, 1997, Nikos Drakos, Computer Based Learning Unit, University of Leeds.
The command line arguments were:
latex2html -split 1 CodingStdC.tex.
The translation was initiated by Ken Clowes on 2000-11-11