1 - Introduction
1.1 Why Have Code Conventions
Code conventions are important to programmers for a number of reasons:
* 80% of the lifetime cost of a piece of software goes to maintenance.
* Hardly any software is maintained for its whole life by the original
author.
* Code conventions improve the readability of the software, allowing
engineers to understand new code more quickly and thoroughly.
* If you ship your source code as a product, you need to make sure it is as
well packaged and clean as any other product you create.
1.2 Coding standards are not programming Standards
The standards and conventions described here are only conerned about coding, i.e. the
layout of the program and the file organization, excluding the standards that
concern the efficiency and performance of the programs. For standards about
the quality of the programs, please check out the book like <C Coding Standards>,
<C Programming Style> and others.
1.3 Acknowledgments
This document reflects the C language coding standards presented in daily
coding, from Alex Hilton. I hope this document will give you some useful help.
When writing this, I have referenced a lot of articles which gave a lot of great
suggestions, including <Elements of programming style> by Brian Kernighan and Plaughter;
<Recommended style and coding standards for c programming laguage> by Iron Moor.
For questions concerning adaptation, modification, or redistribution of this
document, please read our copyright notice.
Comments on this document should be submitted to us in feedback form.
1.4 Copyrights
You are free to use, redistribute and modify without any warntary. This document
is licensed under GPLv2.
For further infomation about GPLv2, please refer http://www.gnu.org
2 - File Names
This section lists commonly used file suffixes and names
2.1 File Suffixes
2.1.1 C language
C source -- *.c
object -- *.o
header file -- *.h
2.2 Common File Names
Makefile -- build our project
README -- summarizes the contents of a particular directory.
3 - File Organization
A file consists of sections that should be separated by blank lines and an
optional comments identifying each section.
Files longer than 2000 lines are cumbersome and should be avoided.
3.1 C Source Files
C source files have the following ordering:
Program source files have the following ordering:
* Beginning with a block of comments summarizing the file.
* Preprocessors: #ifdef, #ifndef, #if
* types: struct, enum, typedef ...
* Function prototypes: private functions, and then extern entricies
* main program
* Function definitions: extern entricies, then the private functions
3.1.1 Beginning Comments
All source files should begin with a block comment that lists the structure
name, version information, date, and copyright notice:
/*
* Filename
*
* Author name, date
*
* descriptions of the program.
*
* Version information
*
* Copyright notice
*/
Many times, it is much better to use a version control like RCS, CVS or SVN.
Then the comment should be like this:
/*
* $Header$
* $Author$
* $Date$
* $Id$
* descriptions
* $Revision$
* $Log$
*/
3.1.2 Preprocessors and Macros
The first non-comment line of most C source should be #include statements. For
example:
#include <stdio.h>
#include <string.h>
The standard headers or other public libraries should be include with ankor
braces, lile <stdio.h> <unistd.h>.
The headers written by you or other programmer should be in quotes, like
"my_debug.h", "my_thread.h".
3.1.3 Function prototypes and types and structures.
3.1.3.1 Function prototypes
Private functions should be qualified with static. You should write a block
comments for each prototype. You should
also include argument variable's names. So we can guess the usage of the
arguments. For arguments like pointers and
arrays, we should qualified const if there is no necessiaty to change the
contents, to avoid unexpected changes.
All external function prototypes should be commented with documentation comments
like this:
/**
* Function: strcpy
* Param: src -- a string from which we copy
* Param: dst -- a string to which we copy
* Return: -1 on error, 0 on success
* Description: strcpy takes two pointers to char as arguments, copying all
* the contents of src to dst.
* Note: This function might ignore null terminator.
*/
3.1.3.2 Types
All structures and unions should be commented with documentation comments like:
/**
* Structure: Point
* Member: x -- x coordinate, in uite(mm, cm or m defined in actual usage)
* Member: y -- y coordinate, the same as x
* Description: Point depicts a geometric point on screen.
*/
struct Point {
int x;
int y;
};
typedef struct Point Point;
4 - Indentation
Two spaces should be used as the unit of indentation. The exact construction of
the indentation (spaces vs. tabs) is unspecified. Tabs must be set exactly every
8 spaces (not 4).
4.0 Do not make any alignment
Except for indentation of statements, do not make any alignments such as
varaible declarations, comments, e.g.:
/* the following should be AVOIDED! */
int i; /* loop variable */
float max; /* max value */
You can just use a space to separate them:
/* the following are correct */
int i; /* loop variable */
float max; /* max value of an array */
4.1 Line Length
Avoid lines longer than 80 characters, since they're not handled well by many
terminals and tools.
Note: Examples for use in documentation should have a shorter line
length-generally no more than 70 characters.
4.2 Wrapping Lines
When an expression will not fit on a single line, break it according to these
general principles:
* Break after a comma.
* Break before an operator.
* Prefer higher-level breaks to lower-level breaks.
* Align the new line with the beginning of the expression at the same level
on the previous line.
* If the above rules lead to confusing code or to code that's squished up
against the right margin, just use your indentation instead.
* Double the standard indentation when wrapping lines.
Here are some examples of breaking fuction calls:
someMethod( longExpression1, longExpression2, longExpression3,
longExpression4, longExpression5 );
var = someMethod1( longExpression1,
someMethod2(longExpression2, longExpression3) );
Following are two examples of breaking an arithmetic expression. The first is
preferred, since the break occurs outside the parenthesized expression, which is
at a higher level.
longName1 = longName2 * (longName3 + longName4 - longName5)
+ 4 * longname6; /* PREFER */
longName1 = longName2 * (longName3 + longName4
- longName5) + 4 * longname6; /* AVOID */
Following are two examples of indenting function declarations. The first is the
conventional case. The second would shift the second and third lines to the far
right if it used conventional indentation, so instead it indents only 8 spaces.
/* CONVENTIONAL INDENTATION */
someMethod( int anArg, Object anotherArg, String yetAnotherArg,
Object andStillAnother ) {
...
}
/* INDENT 8 SPACES TO AVOID VERY DEEP INDENTS */
/* This is usually used in kernel development or where efficiency is important */
void horkingLongMethodName(int anArg,
Object anotherArg, String yetAnotherArg,
Object andStillAnother) {
...
}
Line wrapping for if statements should generally use the 8-space rule, since
conventional (4 space) indentation makes seeing the body difficult. For example:
/* DON'T USE THIS INDENTATION */
if ( (condition1 && condition2)
|| (condition3 && condition4)
||!(condition5 && condition6) ) { /* BAD WRAPS */
doSomethingAboutIt(); /* MAKE THIS LINE EASY TO MISS */
}
/* USE THIS INDENTATION INSTEAD */
if ( (condition1 && condition2)
|| (condition3 && condition4)
||!(condition5 && condition6) ) {
doSomethingAboutIt();
}
/* OR USE THIS */
if ( (condition1 && condition2) || (condition3 && condition4)
||!(condition5 && condition6) ) {
doSomethingAboutIt();
}
Here are three acceptable ways to format ternary expressions:
alpha = (aLongBooleanExpression) ? beta : gamma;
alpha = (aLongBooleanExpression) ? beta
: gamma;
alpha = (aLongBooleanExpression)
? beta
: gamma;
If the assignment statement is too long, but can place in a line, write like
this:
someValue =
someExpression that fill in a line;
Put return type, function name and arguments in a line. If there are too many
arguments or names are too long, put the arguments in the next line using
standard indentation( 2 spaces );
Fox example:
double addDouble(
double doubleArray[], int size, double *result ) {
...
}
int add( int a, int b ) {
...
}
5 - Comments
Implementation comments are meant for commenting out code or for comments about
the particular implementation. Doc comments are meant to describe the
specification of the code, from an implementation-free perspective. to be read
by developers who might not necessarily have the source code at hand.
Comments should be used to give overviews of code and provide additional
information that is not readily available in the code itself. Comments should
contain only information that is relevant to reading and understanding the
program. For example, information about how the corresponding package is built
or in what directory it resides should not be included as a comment.
Discussion of nontrivial or nonobvious design decisions is appropriate, but
avoid duplicating information that is present in (and clear from) the code. It
is too easy for redundant comments to get out of date. In general, avoid any
comments that are likely to get out of date as the code evolves.
Each head char of a statement should be capitcalized. The comments should follow
the general English article conventions.
Note:The frequency of comments sometimes reflects poor quality of code. When you
feel compelled to add a comment, consider rewriting the code to make it clearer.
Comments should not be enclosed in large boxes drawn with asterisks or other
characters.
Comments should never include special characters such as form-feed and
backspace.
5.1 Implementation Comment Formats
C provides comment, /* ... */
use /* ... */ for block comment, esp the description of file, descriptions of
function, or descriptions of structure or structure etc.
use /* */ to comment a line or variables.
e.g. block comment:
/*
* Function: add
* Usage: result = add( a, b );
*
* This function takes two int as arguments and returns the addition of them.
* Pre-condition: ...
* Post-condition: ...
* Return value: ...
*/
e.g. line comment:
....
/* get a value from the user */
value = getValue();
...
int radius; /* in inches */
......
Note: must place a block comment ahead of the file and the function to summarize
the program or function and mention the pre- and post- conditions, and
arguments.
Note: place the line comment for excecutive statements upon the statements, not
end.
e.g.:
...
/* swap two value */
tmp = a;
a = b;
b = tmp;
...
5.2 Doc comments(documentation comments)
Apparently, doc comments are used to generated documetations which extracted later as a guide to your users.
So you should write implementation-free comments, in the standpoint of users and in the specified formats.
Specific formats should be designated by specific documentation-generation tools. In general, we recommend the
following formats:
/**
* description
* Function/Class/Types
* Param:
* returns:
* Note:
*/
Doc comments for instance fields:
/** X coordinate of a point */
/** Y coordinate of a point */
6 - Declarations
6.1 Number Per Line
One declaration per line is recommended since it encourages commenting. In other
words,
int level; /* indentation level */
int size; /* size of table */
is preferred over
int level, size;
Do not put different types on the same line. Example:
int foo, fooarray[]; /* WRONG! */
Note: The examples above use one space between the type and the identifier.
Another acceptable alternative is to use tabs, e.g.:
int level; /* indentation level */
int size; /* size of table */
Object currentEntry; /* currently selected table entry */
6.2 Initialization
Try to initialize local variables where they're declared. The only reason not to
initialize a variable where it's declared is if the initial value depends on
some computation occurring first.
The structure should be intialized like this:
struct Point one[] = {
{ 1, 2 },
{ 3, 5 },
};
If the members are not many, you con fold them into less lines.
The multi-dimensional array should be initialized like this:
const char *month_name[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
"Aug", "Sep", "Oct", "Nov", "Dec",
};
If each item is too long, you can write each item per line.
6.3 Placement
Put declarations only at the beginning of blocks. (A block is any code
surrounded by curly braces "{" and "}".) Don't wait to declare variables until
their first use; it can confuse the unwary programmer and hamper code
portability within the scope.
void myMethod( ) {
int int1 = 0; /* beginning of method block */
if ( condition ) {
int int2 = 0; /* beginning of "if" block */
...
}
}
Avoid local declarations that hide declarations at higher levels. For example,
do not declare the same variable name in an inner block:
int count;
...
myMethod( ) {
if ( condition ) {
int count = 0; /* AVOID! */
...
}
...
}
Always declare variables near where they will be used, and always initialize.
6.4 Declare as late as possible and initialize as soon as possible.
6.5 Declare variables in a minimize scope. When you can declare it as file scope,
do not make it global; when you can delcare it as functional local,
do not make it file scope; when you can make it loop local, do not make it functional loop.
7 - Statements
7.1 Simple Statements
Each line should contain at most one statement. Example:
argv++; /* Correct */
argc--; /* Correct */
argv++; argc--; /* AVOID! */
7.2 Compound Statements
Compound statements are statements that contain lists of statements enclosed in
braces "{ statements }". See the following sections for examples.
* The enclosed statements should be indented one more level than the
compound statement.
* The opening brace should be at the end of the line that begins the
compound statement; the closing brace should begin a line and be indented to the
beginning of the compound statement.
* Braces are used around all statements, even single statements, when they
are part of a control structure, such as a if-else or for statement. This makes
it easier to add statements without accidentally introducing bugs due to
forgetting to add braces.
7.3 return Statements
A return statement with a value should not use parentheses unless they make the
return value more obvious in some way. Example:
return;
return myDisk.size();
return ( size ? size : defaultSize );
7.4 if, if-else, if else-if else Statements
Note: if statements always use braces {}. Avoid the following error-prone form:
if ( condition ) /* AVOID! THIS OMITS THE BRACES {}! */
statement;
7.5 for Statements
A for statement should have the following form:
for ( initialization; condition; update ) {
statements;
}
An empty for statement (one in which all the work is done in the initialization,
condition, and update clauses) should have the following form:
for (initialization; condition; update)
;
When using the comma operator in the initialization or update clause of a for
statement, avoid the complexity of using more than three variables. If needed,
use separate statements before the for loop (for the initialization clause) or
at the end of the loop (for the update clause).
7.6 while Statements
A while statement should have the following form:
while ( condition ) {
statements;
}
An empty while statement should have the following form:
while ( condition )
;
7.7 do-while Statements
A do-while statement should have the following form:
do {
statements;
} while ( condition );
7.8 switch Statements
A switch statement should have the following form:
switch ( condition ) {
case ABC:
statements;
/* falls through */
case DEF:
statements;
break;
default:
statements;
break;
}
Every time a case falls through (doesn't include a break statement), add a
comment where the break statement would normally be. This is shown in the
preceding code example with the /* falls through */ comment.
Every switch statement should include a default case. The break in the default
case is redundant, but it prevents a fall-through error if later another case is
added.
If the falls through is obvious, you can write all of them in a line:
switch ( month ) {
case 1: case 3: case 5: case 6: case 7: case 8: case 10: case 12:
day = 31;
break;
case 4: case 6: case 8: case 9: case 11:
day = 30;
break;
case 2:
day = 28;
if ( leap ) {
day = 29;
}
break;
default:
break;
}
Or, place each case in a line:
switch ( errno ) {
case EIVAL:
case EACESS:
case EBADFD:
err_sys( "errors" );
break;
case NOERR:
/* go on */
break;
default:
break;
}
Avoid too many lines of codes in each case, if you have to do so many things in a case statement, use a
function instead.
switch ( state ) {
case Error:
/* deal with error */
/* AVOID too many lines of codes here, use a function instead */
handleError( );
break;
...
}
7.9 Always braces
No matter how many statements in the control statements( if, do, for, while ...
), always use braces, excluding case statements. And put the semicolon of empty
for and while statements on the next line with standard indentation in order to
be detect more easily.
eg.
for ( tmp = header; tmp != NULL; tmp = tmp->next )
;
...
while ( *p++ == *q++ )
;
7.10 Gathering and dividing
Gather the similar statements to form a block, and divid each block with a space
line.
8 - White Space
8.1 Blank Lines
Blank lines improve readability by setting off sections of code that are
logically related.
Two blank lines should always be used in the following circumstances:
* Between sections of a source file
* Between structure and interface definitions
* Between functions.
One blank line should always be used in the following circumstances:
* Between the local variables in a method and its first statement
* Before a block (see section 5.1.1) or single-line (see section 5.1.2)
comment
* Between logical sections inside a method to improve readability
8.2 Blank Spaces
Blank spaces should be used in the following circumstances:
* A keyword followed by a parenthesis should be separated by a space.
Example:
while ( true ) {
...
}
Note that a blank space should not be used between a function name and its
opening parenthesis. This helps to distinguish keywords from function calls.
* A blank space should appear before and after parethesis, excluding
function and its open parethesis. e.g:
a = ( a + b ) / ( c + d );
ind add( int a, int b );
* A blank space should appear after commas in argument lists.
* All binary operators except . and -> should be separated from their
operands by spaces. Blank spaces should never separate unary operators such as
unary minus, increment ("++"), and decrement ("--") from their operands.
Example:
a += ( c + d );
a = ( a + b ) / ( c * d );
while ( d++ == s++ ) {
n++;
}
printSize( "size is %d/n", sizeof( var ) );
* The expressions in a for statement should be separated by blank spaces.
Example:
for ( expr1; expr2; expr3 )
* Casts should be followed by a blank space. Examples:
myMethod( (byte) aNum, (Object) x );
myMethod( (int) ( cp + 5 ), ( (int) ( i + 3 ) ) + 1);
* Sometimes, when there are so many things in a expression, we should
surpress white spaces to save spaces. But make them into several units by their
functionalities. E.G:
a = ( (c+b) * (e-f) * (g+h) ) / ( (c-d) * (e-f) );
if ( (cond1&&cond2) || (cond3||cond4) || (cond4&&cond5) ) {
...
}
* Always give a space between empty braces, parentheses and brackets, e.g.:
int foo( int a[ ], int size ) ...
rc = fire( );
int foo( ) { }
* Don't add spaces around type in a type cast.
int a = (int) ch; /* no spaces arount int */
double b = (double) c;
* Leave a space before and after comment in a line comment.
/* This is a comment */
* Don't give space for assignments within other expressions
if ( (fp = open( filename )) < 0 ) {
perror( filename );
}
* Add as many spaces as you can when do not violate rules above
9 - Naming Conventions
Naming conventions make programs more understandable by making them easier to
read. They can also give information about the function of the identifier-for
example, whether it's a constant, package, or structure-which can be helpful in
understanding the code.
9.1 Variables
Except for classes, structures, unions, and constants, all other variables or
function names are in mixed case with a lowercase first letter. Internal words
start with capital letters. Variable names should not start with underscore _,
even though both are allowed. We use identifiers begining with underscore _ only
in library headers and their implementations. In your programs, you should avoid
use them to prevent from naming collosions.
Variable names should be short yet meaningful. The choice of a variable name
should be mnemonic --- that is, designed to indicate to the casual observer the
intent of its use. One-character variable names should be avoided except for
temporary "throwaway" variables. Common names for temporary variables are i, j,
k, m, and n for integers; c, d, and e for characters.
e.g.:
int i; /* control flow variables */
char c; /* character for inputing */
float myWidth; /* used for control drawing the face picture. */
9.2 Constants
The names of variables declared constants, macros, enumeration type and of ANSI
constants should be all uppercase with words separated by underscores ('_').
(ANSI constants should be avoided, for ease of debugging.)
e.g:
const int MAX_SIZE = 256; /* ... */
#define MAX_WIDTH 1290 /* ... */
typedef enum { BLACK, RED, ORANGE } COLOR;
#define PI 3.1415926
9.3 Functions
Methods should be verbs, in mixed case with the first letter lowercase, with the
first letter of each internal word capitalized.
run();
runFast();
getBackground();
9.4 Structure
Structure names should be nouns, in mixed case with the first letter of each
internal word capitalized. Try to keep your structure names simple and
descriptive. Use whole words-avoid acronyms and abbreviations (unless the
abbreviation is much more widely used than the long form, such as URL or HTML).
e.g.:
struct Raster;
struct ImageSprite;
Always declare and define structure like this:
typedef struct Point Point;
struct {
int x; /* x co-ordination */
int y; /* y co-ordination */
};
9.5 Files, interface
All files and interface names should be in lowercase, and short, effective,
descriptive. Avoid using any character other than letters.
Note: strive to make the identifiers short, effective and descriptive and
readable.
length is 3 to 8 is best.
9.6 Naming convention of UNIX/LINUX
The conventions discussed above are for general purpos. When in special case, we
have to use special one.
The UNIX/LINUX likes all identifiers are short, usually abbreviated, all in
lowercase and conjuncted with underscores.
int fd_flag;
struct stat;
int total_count;
double cur_money; /* in US dollar */
fcntl( ... );
int memcpy( ... );
int memset( ... );
void *malloc( ... );
The keywords of C and its standard libraries, the system libraries of UNIX/LINUX
and the structures of UNIX/LINUX are good example.
9.7 Constants
The constants here are not const variables, but nemeric constants like 1234,
495.57.
Generally speaking, we should not use any magic numbers in our program. We use
macros or enums instead.
And it is a good idea to specify the type of contsants when writing it. There
are some suffixes for doing this like
l, L, f, F and u, U, u or U should combined with f,F, l and L. For clarity, you
not use lowercase l, you should use
L, F, f, u and U always. I prefer f, u and L. And you should always add suffixes
for constants. And when combining,
the case should agree, not uL or Ul, but UL, ul, (ul is not recommended, of
course).
#define BUF_SIZE 3456778UL
glVertext3f( 0.f, .1f, 5.f );
9.8 Local Variables and global variables and variable lengths
The length of a name should reflect its scope. A local variable in a small
function has very limited scope. Here, max might be a suitable name although
maxTemp is probably better. A global variable has wide scope. Globally, we might
need a name like maxTempForMostRecentSAO.
9.9 About Prefix and suffix of an identifier
Generally speaking, adding prefix and suffix to a variable name or function name
is a bad idea. But There are some
exceptions. If some variables or functions are in the same class except some
trivival differences, then we and use
prefix or suffix to distinuish them. By convention, the prefix is major
classification, suffix is minor
classification. This is also one way to implement overloading which is instinct
in
some OO language like C++ and Java. Good examples are OpenGL and GTK+ functions.
We use prefix to distinguish
different libraries, classes or structures. We use suffix to distinuish
different functions working for
one purpose(implementing overloading).
glVertex3f( 0.f, 1.f, 2.f );
glVertex3d( 1, 2, 4 );
glVertex3ud( 2u, 4u, 5 );
GL_PI;
GTK_WINDOW_TOPLEVEL;
GTK_PI;
GTK_E;
g_get_home_dir();
g_strcmp();
gtk_button_new();
gtk_button_new_with_label( label );
gtk_button_new_with_mnemonic( label );
[References]
<Java Coding Convention>, 2001, Sun Microsystems Inc.