Coding standards are by far one of the most over looked and unthought aspects of writing good code. It falls into a selection of material, which I find myself being increasingly more opinionated about. Unfortunately many people don’t see the importance of a strict style guide, or following best practices, and this generally leaves you high and dry with a clump of unmaintainable code.

Following a code style guideline strictly means that your code becomes far more readable, and this fact alone has a huge influence on the maintainability if it. I am by no means saying there is a single conclusive “best style guide” for any language, but there are definitely some which are better than others.

The other critical aspect people miss when designing a style guide is that they believe it is a once off process. They come up with some set of rules, often seemingly arbitrarily with little motivation, and then they forget about it. They never adapt it, they never enforce it, they just send it out and hope everyone applies. In my opinion this is incorrect, we live in an ever evolving world, technology, best practices, hardware everything evolves and your style guide should be no exception. If you come across a new way of doing something that makes more sense, then throw out your current way of doing it and enforce the new way. We live in the 21st century there are tools to automatically apply most of your style guide to existing code, as well as tools to check people are using it properly.

This aspect of creating a style guide and never updating it is probably the part that irks me the most. For instance, the number of company style guides which still require an 80-character max is ridiculous. Who doesn’t have a wide screen these days, it’s not like anyone actually bashes out production code on a 24×80 terminal anymore, well not at any place I have worked. Thus that restriction is pointless at the companies which I have worked at. It should not be there any more, it forces line breaks in places that don’t always make sense, thus making reading the code far more difficult, and furthermore increasing the possibility of bugs.

So what should it look like?

I think you should have an idea of what I am implying a style guide should and shouldn’t be and why I feel it is important, but I don’t feel this post would be complete without an example of what a good style guide is. For me there are few guides better than John Carmack’s C style guide used in Quake 3, or his C++ guide for Doom 3. There is also an excellent review of the coding standard used in there two engines at: http://kotaku.com/5975610/the-exceptional-beauty-of-doom-3s-source-code

For this reason it was an obvious place or me to start when I created my style guide. I primarily write C code for embedded systems and thus had to tweak a few things here and there, and add a few extra rules to what is and isn’t allowed, so that it all works better in the embedded systems world. My guide is by no means perfect, but then I don’t think any guide is, I am continually evolving it and updating it so what it is today and what it might be next year might not look at all the same.

So without further waffling, here it is with some motivations.

General

Spacing:
Use real tabs that is preferred to equal 4 spaces.

This one gets me a lot of flack, the first argument everyone makes is that Joel Spolsky and Jeff Atwood both think people who use real tabs are dumb asses. Well to be perfectly honest, I couldn’t care what they thought. I have a few of my own motivations why tabs are better. 

  1. Tabs are a single character ASCII(#9), thus to get nice indentation we use 1 char instead of 4 and so source files are smaller.
  2. Typing code is quicker, although you couple set a tab to be equal to 4 spaces in most IDEs
  3. Indentation is guaranteed and dynamic, people can’t pop in 5 spaces by accident or something like that.
  4. Each developer can change the level of indentation to suit their preference/set-up. The guy coding in portrait can set a tab to be 2-spaces so everything fits. While the guy on the 27″ can set it to be 8-spaces so he can see levels of indentation easily. The best part is that making these adjustments has no effect on the next guy working on the file. 

Lines Spacing:
One new line between the functions

I don’t have much motivation for this, I just feel it looks nicer.

Braces:
Always open following a statement. Never opening on a new line.

void some_function( int x )  {

}

Instead of

void some_function( int x )
{

}

Use trailing braces everywhere (if, else, while, for, structs, etc)

if ( x ) {

}

Else statements start on the same line as the last trailing brace

if ( x ) {

} else {

}

Note the single space before the opening brace.

Using braces in such a way not only saves you one line per function or statement, but it also guarantees that you don’t accidentally add code between the if statement and the brace, which could lead to undefined behaviour. Let’s look at an example:

if ( color == RED )
{
led_flash_red();
}

Could be come

if ( color == RED )
clear_led();
{
led_flash_red();
}

where using a trailing brace will ensure this cannot/is far less likely to happen. I know this seems silly but it happens, I have seen it. It happens even more when you have a bunch of strange #defined in between the if statement and the braces.

Using braces for single line if statements or for-loops is a MUST, and probably the most non-negotiable part of my style guide. There is absolutely no benefit to leaving them off. I have seen too many errors where a line is commented out, but not the if statement, thus causing the if to be applied to whatever the next line is. 

Padding:

Always pad brackets with spaces:
some_function( x );
instead of
some_function(x);
or
( x + y )*2;
instead of
(x+y)*2

I find this just eases readability of the code. Everything is nicely spaced and easy to follow.

Number Formats:

Always specify precision for floating points
x = 1.0f;
instead of
x = 1; or x = 1.0;

This just clears up any confusion, and ensures the compiler actually does what you intended.

Naming Conventions:

Functions are named using lowercase letters and an underscore word seperator

void this_is_a_function_name( void );

Recursive functions are appended with an _r

void calculate_nth_fibo_r( int n );

Functions with long argument lists can use multiple lines, but must indent the argument list such that the first argument on new line is aligned to the closest tab to the first arguments alignment.

void some_function_with_long_arg_list( int first_arg, char second_arg, unsigned char another_arg
uint32_t this_is_the_final_arg );

Variables use the same naming convention as function names.

int this_is_a_variable;

Pointers are defined with the same convention as variables, but are suffixed with _ptr except in the case of the pointer being a string (char *)

uint8_t *file_list_ptr;

type definitions and structures use camel case starting with a small letter and always end with a _t

typedef int fileHandle_t;
struct fileSystem_t;

enums use the same convention as structs and typedefs however, enum constants are always uppercase and use an underscore word seperator. Enum constants must always be follows by a comma (even the last element, unless the enum cannot be extended past the last element) and it is strictly one constant per line. As with all other braces, the opening brace starts immediately and onto on a new line.

enum fileType_t {
DIRECTORY_TYPE = 0,
IMAGE_TYPE,
AUDIO_TYPE,
};

#defines are named using the same conventions as enum consts. All uppercase with an underscore seperator. Tabs are used to align all #define definitions in a file.

#define SAMPLING_RATE 600000
#define BUFFER_SIZE        16

Enums:

Enums are an interesting case, and I recently changed the way I define them. In the embedded systems world it is often required that an enum be of a specific size i.e. 8-bits. This can lead to issues if defining an enum typedef in the normal way as often the compile will optimise the enum to use the most efficient data type (32-bits on most ARM systems). So I changed the way I define enums to guarantee they are of the correct size.

“Normal way”

enum fileType_t {
DIRECTORY_TYPE = (uint8_t) 0,
IMAGE_TYPE,
AUDIO_TYPE,
};

It is possible that in this case the compiler will ignore the the casting to (uint8_t) and will instead define the enum using a uint32_t. This can lead to strange behaviour when packing structs which contain enum types. Instead we define enums as:

typedef uint8_t fileType_t; enum {
DIRECTORY_TYPE = 0,
IMAGE_TYPE,
AUDIO_TYPE,
};

I am aware that this will prevent compiler warnings if you try assign a standard uint8_t to the enum type, but I feel that guaranteeing bit packing is a better feature. Debugging funny bit packing due to optimisations can really drive you mad, while assigning the wrong value to an enum type can easily be checked with an assert statement. In systems where bit packing isn’t used heavily then the standard enum definition can be used. The trick is to be consistent.

Functions:

Functions without parameters must specify ( void ) as the parameter list, inline with the C standard.

functions must begin with the following header:

/**
* Function Name
* Function description goes here
* Continues here….
**/

This description is a bit of a worry for me still, as block comments “/* */” are not officially part of the C99 standard, and thus could cause issues in some cases. However, most compilers have included this functionality in them and thus I allow block comments. If for some reason they cause an issue my solution would be to just use the same header with single line comments “//”

Functions which do not change parameters must be marked as const and all parameters must be marked as const.

uint32_t str_length( const char* str ) const;

Functions which are only defined in a C file, and not exposed via a public or private header file should be defined as static, or static const if it applies.

static uint32_t str_length( const char* str ) const;

This is another rule which I don’t think gets enough weight. I find that in general people do not enforce immutability on their variables, and do not use the static key word enough to limit the function scope. Using these two keywords can decrease silly errors and strange bugs significantly.

Variables:

Every variable is defined on its own line, even if they are of the same type. Furthermore, variable declarations must be tabbed to a consistent indentation and should never be initialised inline, unless they are static. All static variables should be declared first in the list and there should be a single line separating static and non-static declarations.

Variable initialisation should take place at the last possible point in a function that is can as this allows for better compiler optimisations and reduces the amount of data pushed to the stack upon entering a function.

Best case:

static uint32_t x = 1234;

uint8_t y;
bool done;

y = 4321;

.. do stuff …

done = false;
..do more stuff…

if ( ready() ) {
done = true;
}

Variables must be named with descriptive names such that they are self describing. Exceptions are made for variables used as iterators (e.g. i,j,k) or generics such as “ret” for a return value.

All variables must be defined as const, unless they are not. Pointers must be defined as const pointers, const pointers to const values, or pointers to const values. i.e.

const int *const p; // const pointer to const int
int *const p; // const pointer to int
const int *p; // pointer to const int

Furthermore, the static keyword should be used to limit the scope of variables which are defined globally but not exposed via the extern keyword in a header file. Better yet try an encapsulate as many static variables within local functions as static variables rather than as generic global variables.

This guide is my no means complete, I am still missing information on header files, loops, asserts, switch statements and a ton more. ut for now this will give you the basics. I will continue adding to this list as I can.