Daniel Verkamp :: C Coding Style

Coding conventions are always a favorite topic of argument among programmers, and I am no different in this respect. Therefore, I have laid out my thoughts on the matter, specifically relating to the C programming language, in the hopes that someone will find them useful (and also so that I can point at this page when someone speaks to the contrary). None of this is set in stone; anyone who sets an exact "standard" has probably not written enough code to understand why such restrictions on coding style are bound to fail. Therefore, these observations are more guidelines than laws. Some of these recommendations are "common sense", but one should not assume that such sense is as common as it might seem.

Use tabs for indentation, not spaces. There are few reasons to use spaces and many reasons not to use them. If you use tabs, someone reading your code can easily change indentation depth - perhaps he prefers 2 spaces per tab, whereas someone else might consider this unreadable and choose 4 spaces per tab instead. In any case, this is impossible when spaces have been used for indentation. Also, using tabs makes it easy to remove one level of indentation at a time with the backspace or delete key; this is not usually possible with spaces, since the editor generally does not know that sets of a certain number of spaces are to be treated as a single unit. Some editors do support this, but code should not force a particular editor on anyone.

On the other hand, always use spaces for lining up code on multiple lines, not tabs. For example:

#define FOO_XYZ     123
#define FOO_ABCDEF  42
#define FOO_BLAH    31415
Using tabs here is a bad idea, since the number of tabs required on each line would depend on the size of a tab.

In general, whitespace is your friend. A little extra whitespace won't break the budget or overflow your hard disk, and it will improve readability immensely. Instead of:

#include<stdio.h>
int main(int argc,char**argv){
	if (argc==1) printf("Hello, world!\n");
	else printf("Hello, %s!\n",argv[1]);
	return 0;
}
Write something like this:
#include <stdio.h>

int main(int argc, char **argv)
{
	if (argc == 1)
		printf("Hello, world!\n");
	else
		printf("Hello, %s!\n", argv[1]);

	return 0;
}
Your code won't run any faster just because you squished the source file into half the size by reformatting it.

Always indent multi-statement blocks of code. Don't put multiple statements on one line. Whatever you do, don't indent the braces an extra level (the GNU Coding Standards recommend this, but it looks like a mess - and they prefer spaces for indentation...). Put the opening brace of a block in the same column as the code above it or on the end of the line of the conditional statement. Braces that surround the contents of a function should always be on a line by themselves, since they are "special" (they can't be nested, for one thing).

Don't use compiler- or platform-specific extensions unless you absolutely must. This includes things like the GNU C extensions; even if you think your code will only ever be compiled by GCC, perhaps someday someone will want to build it with MSVC or OpenWatcom or Borland C or some other compiler that doesn't support those extensions... If you really must use an extension, try to keep the non-standard bits of code in a separate portability layer that can be easily rewritten for different platforms.

Don't use // C++ comments in C programs; use /* C comments */. This is really just an extension of the rule about extensions (pardon the pun) - C++ comments are not standard C(89), so avoid them unless you have a really good reason (which you don't, because normal C comments are perfectly good at commenting things). C++ comments can be especially dangerous in multi-line preprocessor macros:

#define XYZ(a)        \
        // frob 'a'   \
        frobnicate(a)

Never write code like p = realloc(p, size); - this is a memory leak. Assign the return value of realloc() to a temporary pointer and check if it's NULL first, in which case you still need to free() the original block of memory. Otherwise, copy the temporary pointer back to the original.

Use as many parentheses as you need to be comfortable with the order of operations. If you don't have the precedence of every operator memorized (which is useful, perhaps, but not necessary for writing good code), just add a few parentheses to force the order you intend. Leaving out parentheses can lead to unintended consequences: x & 3 == 1 is the same as x & (3 == 1), not (x & 3) == 1. Also, always surround preprocessor macro parameters with parentheses wherever they are used in the macro's definition. Remember that the preprocessor only does text substitution, so complex expressions used as macro parameters will break things unless parentheses are used.

Keep functions short. The average function should fit on an 80x25 terminal. If a function is larger than this, its purpose is probably not clear enough anyway; split it up into multiple smaller, better-defined functions.

Turn on your compiler's warnings if you haven't already and carefully examine any warnings reported by the compiler. Don't rush to insert a quick fix; the warning might be indicative of a deeper problem. For example, don't throw in random casts to appease the compiler. Consider using a lint-like program as well.

Always declare pointers with the * next to the identifier, not the type:

int *x;         /* good */
int* x;         /* bad */

int *x, *y, *z; /* declares three int pointers (good) */
int* x, y, z;   /* declares one int pointer and two ints (bad) */
Also remember that typedefs are smarter than plain text substitution:
typedef int *intptr;
intptr x, y, z; /* declares three int pointers (good) */

#define intptr int *
intptr x, y, z; /* declares one int pointer and two ints (bad) */

Write what you mean: for example, if you want to divide by two, write (x / 2), not (x >> 1). Let the compiler pick the best way to perform the operation by telling it what you want it to do.