This document covers coding guidelines to use when writing C code.
It is expected that code refactoring will follow this ForgeRock C coding standard, unless specific circumstances dictate how the code is to be formatted. Following the FR coding standard should guard against 'bit-rot' or source code unravelling.
All new source files must begin with the same copyright notice as recommended in the Coding Style and Guidelines
This style is mainly oriented around the desire to make C code more readable. Unless otherwise stated, the Kernighan and Ritchie style (otherwise known as "Egyptian Style") reigns supreme. This basically boils down to:
compound-statement { statement-1; statement-2; } |
No other variations should be used, especially not the infinitely ugly GNU C style:
compound-statement { statement-1; statement-2; } |
The ForgeRock C code style rules are based on the Coding Style and Guidelines except that I think we can safely ignore the 120 character column limit on line lengths - we have big screens.
Consider the following example for a few of the points listed above:
int my_func(int *p,int c) { unsigned int *index = p + c - 1, entry_index=0; if (index) *index=entry_index; } |
should be written as:
/****************************************************************************************** * The function my_func divides by the number you first thought of, which is useful when * parsing HTTP header information. * Parameters: * int_base is a pointer to a block of memory containing a series of signed integers * count is the number of signed integers in the block pointed to by "int_base" * Return: * If successful, the function returns 1, if unsuccessful, the function returns 0 ******************************************************************************************/ int my_func(int* int_base, int count) { unsigned int *index = int_base + count - 1; unsigned int entry_index = 0; if (index != NULL) { *index = entry_index; } entry_index = sizeof(int); // etc. etc. } |
A regrettable feature of the ISO C standard was that preprocessor constants are not allowed after #else and #endif. Things can quickly get confusing, for example:
typedef struct { #ifdef _WIN32 SOCKET sock; HANDLE pw; CRITICAL_SECTION lk; HANDLE tm; HANDLE tm_tick; #else int sock; pthread_t pw; /*event loop*/ pthread_mutex_t lk; #ifdef __APPLE__ pthread_t tm_th; pthread_mutex_t tm_lk; pthread_cond_t tm_cv; #else timer_t tm; #endif #endif } |
Therefore #else and #endif should ALWAYS be commented as follows:
typedef struct { #ifdef _WIN32 SOCKET sock; HANDLE pw; CRITICAL_SECTION lk; HANDLE tm; HANDLE tm_tick; #else /* _WIN32 */ int sock; pthread_t pw; /*event loop*/ pthread_mutex_t lk; #ifdef __APPLE__ pthread_t tm_th; pthread_mutex_t tm_lk; pthread_cond_t tm_cv; #else /* __APPLE__ */ timer_t tm; #endif /* __APPLE__ */ #endif /* _WIN32 */ } |
Use of the defined
operator should be considered over the #ifdef and #ifndef directives, because defined
allows for combinations. This gives a syntax error:
#ifdef _WIN32 && !SOLARIS |
whereas this works as expected:
#if defined(_WIN32) && !defined(SOLARIS) |
You could consider using Doxygen, http://www.stack.nl/~dimitri/doxygen/ which allows documentation to be generated from annotated source code, in which case the above would become a much more familiar:
/****************************************************************************************** * The function my_func divides by the number you first thought of, which is useful when * parsing HTTP header information. * @param int_base is a pointer to a block of memory containing a series of signed integers * @param count the number of signed integers in the block pointed to by "int_base" * @return If successful, the function returns 1, if unsuccessful, the function returns 0 ******************************************************************************************/ int my_func(int* int_base, int count) { unsigned int *index = int_base + count - 1; unsigned int entry_index = 0; if (index != NULL) { *index = entry_index; } entry_index = sizeof(int); // etc. etc. } |