No Clean Feed -
            Stop Internet Censorship in Australia

Coding style

I am a big aficionado of writing clean, nice-looking code. This extends to all the languages I write in, however this style guide mostly focusses on C.

First off, I would like to make it perfectly clear that this is my preferred coding style guide. I do not (and will not) force this style on any one else: coding style is a personal thing.

Second, my coding style is heavily based on the K&R style (which, as we all should know, is the correct style, since K&R are teh gods. If in doubt, do what K&R did.

This page primarily exists to document the differences my style makes from K&R, nothing more.

Contents

Line length

All lines must be maximum of 79 characters wide. No exceptions. It is too difficult to quickly skim a large amount of code if it won't fit inside a terminal without overflowing.

Indents

Indents are 4-characters of whitespace. That is, 4 spaces. Do not insert tab characters.

while (1) {
    printf("see, 4 characters\n");
}

The Linux kernel coding style makes an interesting point to counter what fans of 4-characters (me) often use as an argument:

Now, some people will claim that having 8-character indentations makes the code move too far to the right, and makes it hard to read on a 80-character terminal screen. The answer to that is that if you need more than 3 levels of indentation, you're screwed anyway, and should fix your program.

I happen to agree with the last bit, but I still prefer 4 spaces.

Line continuations consist of double tab stops:

printf("this is a really long line that needs to be split over multiple"
        "lines and hence gets double tab stops\n");

See also line length.

Spacing

Use spaces around components of a statement, such as operators, variables and brackets. The only exception here is to not space the inside of brackets.

Good:

if (foo != bar) {
    memcpy(bar, foo, strlen(foo));
}

The idea here is readability.

Function & variable naming

Camel case is for Microsoft developers who want to feel special. Instead, use underscores_if_needed:

unsigned char sing_a_song(void)
{
    unsigned char song_key = 'C';
    return song_key;
}

Braces

Follow K&R to the letter with bracing. An example of correct bracing is (taken from Ulysses' libc):

void *memcpy(void *dest, const void *src, size_t n)
{
    char *d = (char *)dest;
    char *s = (char *)src;
    while (n--) {
        *d++ = *s++;
    }
    return dest;
}

Note that function braces do not hug, yet all other statements do.

Omitting braces is allowed, so long as they hug the statement:

Good: if (foo != bar) do_stuff(foo);
Bad:

if (foo != bar)
    do_stuff(foo);

The reason this is bad is because it is too easy to notice the indent and add another line of code to the statement, yet forgetting to add braces. This of course would not be the desired effect!

If in doubt, always add braces.

Function prototypes

I am very picky about function prototypes. A function should always be declared static, unless required to be exported to other modules.

Always use void instead of empty brackets:
Bad: some_func()
Good: some_func(void)

Declare the entire function on one line! None of this splitting return type and parameters on to different lines (cough ast).

Every function should have a description directly above it, describing what it does and what it returns. This can simply be a free-text description, no Javadoc-style commenting is required.

A static function should have its description placed with the declaration in the .c, whereas a non-static function should have its description with the prototype in the file's corresponding .h.

The first line in the description should be the name of the function with empty braces directly after it: like_this(). Every other line should be indented by 2 spaces. This helps set it apart, as well as confusing just about every person who isn't expecting it (don't ask me why I do this, I have no idea).

Example:

file.c:

/* counter()
 *   Increments the global variable help by one.
 */
static void counter(void)
{
    help++;
}

unsigned int num_helps(void)
{
    counter();
    return help;
}

file.h:

/* num_helps()
 *   Returns the number of times help has been incremented.
 */
 unsigned int num_helps(void);

Comments

Under no circumstances use C++-style comments: //. I just hate them. All comments should use K&R's style of /* */. Compiling with -ansi helps remind one, although this disables some other cool things that aren't part of the standard.

Single-line comments should be brief, informative snippets to show meaning of a statement or variable. They should follow proper grammar, but do not need to have a tailing full stop:

/* Something like this is quite appropriate */ 

For multi-line comments each line should be aligned with the starting *:

/* This is a multi-line comment here.
 * See how it lines up on the left, and looks nice
 * and neat. The terminating line should also align.
 */

Don't leave the first line blank, and make sure to write multi-line comments in proper paragraphs, with proper grammar.

To comment out blocks (or even single lines) of code, use preprocessor conditionals:

#if 0
    code_that_should_not_be_executed();
#endif

Most good editors will see this as a comment and highlight it as such for you. The reasoning is two-fold:

  1. K&R comments cannot be nested
  2. You are commenting out code for a reason: you don't want it to be in the executable

TODOs

Inline TODOs should be single-line comments prefixed with XXX, and contain proper grammar (the first word after XXX should not be capitalised):

/* XXX really need to check for bounds here */

Don't use the TODO keyword; XXX is much easier to notice when quickly scanning a block of code.

Any TODOs that require more than a single-line comment should really be fixed on the spot, while the reasoning is still clear — don't put off the inevitable!

Compiler warnings

I am a big fan of writing code that generates no warnings when compiled. Warnings are (usually) there for a reason: they indicate you are possibly going to get a result you didn't expect.

Therefore I compile code with -Wall -Wextra -Werror. This turns all warnings into errors, failing the compile if generated.

Other stuff

These sections aren't really about style, but are still relevant, so are included here nonetheless.

Editor choice

Here's my stance on the war: vim.

Toolchain

I use gcc-4.3.3 for a C compiler, nasm for the small amounts of (Intel-style) assembler I write, and the GNU linker (ld) for linking object files.

Instead of make, I use SConstruct.