The content of this document has been
extracted from Tcl/Tk
Engineering Manual", by J. K. Ousterhout, May 1996.
This is a simplified and slightly modified summary of the above
document which is in turn is a manual for people who are developing C code
for an application called Tcl/Tk. It describes a set of conventions for
writing code. Ousterhout mentions three reasons for the conventions:
- ensure that certain important things get done: for example, every
procedure must have documentation
- guarantee all the code has a uniform style. This makes it easier to
use, read and maintain.
- help to avoid some common mistakes by prohibiting certain constructs
in C such as ++ and -- operators in the middle of
expressions (for example in a condition of an if-then-else).
Please, write your code so that it conforms to these conventions from
the very start.
General Conventions
- Each source code file should contain a related set of procedures.
Before writing code you should think carefully about what functions are
to be provided and divide them into files in a logical way. C files
should not have more than 2000 lines.
- Each procedure should be preceded by a header that gives overall
documentation followed by the declaration and the body. The header is
written as a comment and should include the name and a brief explanation
of the procedure, explanation about the result that it returns (if any)
and finally, side effects that might occur.
- Procedure declaration should include as the first line the type of
the procedure's result. All procedures must be typed. Use void if there
is no result. The second line gives the name and its argument list. If
they are too many, they may spill into several lines.
- Order the parameters in a declaration by relevance. Most important
parameters go first.
Naming Conventions
The ideal variable name is one that instantly conveys as much
information as possible about the purpose of the variable it refers to.
Some things to consider are:
- Are you consistent? Use the same name for the same thing everywhere.
- Could this name be confused with some other name?
- Is the name so generic that it doesn't convey any information?
It follows a set of specific rules governing syntax of names.
- Variable names must start with lower-case letter. Procedure and
defined type names always start with an upper-case letter.
- In multi-word names, the first letter of each trailing word is
capitalized.
int counter;
extern char *FindElement();
typedef int Boolean;
- Any name that refers to a pointer ends in Ptr. If a name refers to a
pointer to a pointer, then it ends in PtrPtr, and so on. The rule does
not apply to strings, despite the fact that are represented as pointers
to char, the suffix Ptr is not needed.
TkWindow *winPtr;
char *name;
char **namePtr;
- Constants defined with #define should have names with all capital
letters. Macros that code simple procedures should have only the first
letter capitalized.
#define NULL 0
#define BUFFER_SIZE 1024
#define Min(a,b) (((a) < (b)) ? (a) : (b))
Low-level coding conventions
- Each level of indentation should be four spaces. Set your favourite
editor to follow this basic rule.
- Code comments occupy full lines. Comments that document code should
occupy full lines rather than being tacked onto the ends of lines
containing code. The comment should be indented to the same level as the
surrounding code.
- When documenting the arguments for procedures and the members of
structures, place the comments side by side on the same lines as the
declarations.
typedef struct VarTrace {
Tcl_VarTraceProc *traceProc;/* Procedure to call when operations given
* by flags are performed on variable. */
ClientData clientData; /* Argument to pass to proc. */
int flags; /* What events the trace procedure is
* interested in: OR-ed combination of
* TCL_TRACE_READS, TCL_TRACE_WRITES, and
* TCL_TRACE_UNSETS. */
struct VarTrace *nextPtr; /* Next in list of traces associated with
* a particular variable. */
} VarTrace;
- Curly braces: { goes at the end of a line. They should not
appear on lines by themselves. Instead, they should be plaed at the end
of the preceding line. Closed curly braces always appear as the first
non-blank character on a line. Always use curly braces around a compound
statement even if there is only one statement in the block:
/* INCORRECT */
if (filePtr->numLines == 0) return -1;
/* CORRECT */
if (filePtr->numLines == 0) {
return -1;
}
There is one exception, when cascading else statements you may use a
form like the following if (strcmp(argv[1], "delete") == 0) {
...
} else if (strcmp(argv[1], "get") == 0) {
...
} else if (strcmp(argv[1], "set") == 0) {
...
} else {
...
}
- Stick to lines with no more than 80 characters. If a line is longer
than 80 characters, break its content into a continuation line.
Continuation lines are indented 4 more spaces than the line before, to
avoid confusion. Pick clean places to break your lines.
- Switch statements have two levels of indentation, one for the
switch keyword and one for each case statement:
switch (src) {
case `n':
dst = `\n';
break;
case `t':
dst = `\t';
break;
...
}
- Avoid macros except for simple things.
- Always parenthesize expressions. They are easier to read.
/* INCORRECT */
if (x > 22 && y <= 47) ...
/* CORRECT */
if ((x > 22) && (y <= 47)) ...
Documenting code
- Document things with wide impact. The most important things to
document are those that affect many different pieces of a program.
- Don't just repeat what's in the code:
/*
* Increment i.
*/
i += 1;
Documentation should provide higher-level information about the
overall function of the code, helping readers to understand what a
complex collection of statements really means. For example, the comment
/*
* Probe into the hash table to see if the symbol exists.
*/
is likely to be much more helpful than *
* Mask off all but the lower 8 bits of x, then index into table
* t, then traverse the list looking for a character string
* identical to s.
*/
- Document each thing in exactly one place. If something is documented
in several places, it will be hard to keep the documentation up to date
as the system changes. Instead, try to document each major design
decision in exactly one place, as near as possible to the code that
implements the design decision.
- Document as you go. It is extremely important to write the
documentation as you write the code. It's very tempting to put off the
documentation until the end; after all, the code will change, so why
waste time writing documentation now when you'll have to change it
later? The problem is that the end never comes there is always
more code to write.
- Document tricky situations. If code is non-obvious, meaning that its
structure and correctness depend on information that won't be obvious to
someone reading it for the first time, be sure to document the
non-obvious information.
|