Skip to content

Instantly share code, notes, and snippets.

@nicholatian
Forked from huderlem/style-guide.md
Last active May 27, 2020 06:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nicholatian/2d9514feaf9a95e7561a433ac404b141 to your computer and use it in GitHub Desktop.
Save nicholatian/2d9514feaf9a95e7561a433ac404b141 to your computer and use it in GitHub Desktop.
Style guide for ANSI C projects

Style guide for ANSI C projects

Version 1

Comment usage

All comments are block style. When continuing onto multiple lines, prepend * at the start of each new line, like so:

/* start of a comment
 * continuing a new line
 */

Apply a comment after #endif directives referencing the corresponding identifier, when the #if block is lengthy (use discretion), like so:

#ifndef WIN32_LEAN_AND_MEAN
#error "no"

/* ... */
#endif /* WIN32_LEAN_AND_MEAN */

To section out portions of code in exclusion from compilation, use the #if 0 trick, like so:

void foo( void )
{
	int i, j;
	
	/* ... */
#if 0
	/* The_BAD_Code (!!!) */
#endif
}

Identifier naming

Use snake_case for all identifiers, in uppercase for constant values and lowercase otherwise. Note that const variable declarations are not considered ‘constant’ for this purpose. All identifiers exposed by the CPP should be in uppercase.

Always prefer shorter identifiers to longer ones. Do not exceed 31 characters in symbol names, as this is considerate to memory-constrained compilers. Use comments to explain identifiers instead.

#define MY_DEFINE 111
#define MAC_RO_FO_SHO(xx) \
	(xx ? 69 : 420)
/* xx is not exposed by the CPP, so it is not uppercase */

const int examp = 13;

void far_func( int, int* );

int sigh( void )
{
	int x;

	far_func( 42, &x );

	if( examp > x )
	{
		x *= MAC_RO_FO_SHO( examp );
		x /= 2;
	}

	return x + MYDEFINE;
}

Whitespace

Always use hard tabs for indentation. Configure auto-formatters to treat sources with 8-character-wide tabs, so that editors will display well with this width or less. Do not exceed 79 characters in width, as this is considerate to terminal editing. The exception to this rule from linux applies, so disregard the rule for constant char* expressions.

Separate blocks with blank lines. Collections of similar adjacent code can be separated from one another with blank lines as well (use discretion).

A single space should follow an opening parenthesis and precede a closing parenthesis. Parenthetical statements should have their identifiers or keywords immediately followed by the opening parenthesis (ergo, no space in between). Square brackets should not have any spacing surrounding them.

Prefix and postfix operators should immediately precede or follow their identifiers, respectively. Align the indentation of case statements with their corresponding switch keywords.

foo++;
++bar;

switch( baz )
{
case 'A':
	bar++;
	break;
case 'B':
	bar--;
	break;
default:
	bar = 1;
	break;
}

Curly braces

Allman-style bracing is used throughout, however Curly braces for initialiser lists should have the opening brace on the same line as the equal sign =. Always use braces with block statements, even when they are one line (also, consider ternary conditionals).

const int sup[5] = {
	1, 2, 3, 4, 5
};

Control flow

Use falsey values to indicate success wherever possible, but note deviations from this wherever necessary. Store the result of boolean expressions as ints, if necessary, but avoid storing boolean values wherever possible.

Terminate case statements with break statements unless there is an intentional fall-through. Comment to note fall-throughs.

Use prefix increment/decrement instead of postfix inside for loops, as this is considerate to antique compilers.

Use discretion to apply ternary conditional expressions in place of unwieldy conditional blocks.

extern struct state s;

while( !mainloop( &s );

switch( bla )
{
case '-':
case '_':
case '=':
	return 0;
	break;
case '+':
	ble++;
	/* fall-through */
default:
	ble++;
	break;
}

int foobar( void )
{
	volatile int reee = 5555;
	
	return 55555 >= reee ? 32 : 640;
}

Types and C ‘namespaces’

Do not typedef struct or enum definitions. Do not assume any typing about enums and likewise do not use enum names as types. Additionally, do not name enums (though they may be ‘named’ informally with a comment in its place). Use typedefs to specify function pointer signatures, and to alias primitives for flexibility. C’s struct and enum keywords constitute namespaces (unrelated to C++ namespaces) that distinguish them from primitives.

/* incorrect */
enum mycoll
/* correct */
enum /* mycoll */
{
	MYCOLL_FOO, MYCOLL_BAR, MYCOLL_BAZ
};
/* incorrect */
enum mycoll foo = MYCOLL_BAZ;

/* correct */
int foo = MYCOLL_BAZ;

/* incorrect */
typedef struct
typedef struct blah
/* correct */
struct blah
{
	int a, b;
	char c[5];
/* incorrect */
} blah_t;
/* correct */
};

/* incorrect */
typedef struct blah blah_t;

/* correct */
typedef void (*myfunc)( int, int );
typedef u16 mapid_t;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment