Style Guide
Comments
A comment shall not appear on the same line as code.
Comment Delimiters
A comment is introduced with the characters /*
and terminated with the
characters */
.
Example
/* This is a comment */
Single Line Comments
A single line comment shall be placed on its own line and be indented to the same level of the code which immediately follows it.
If no code follows the comment then it shall not be indented.
Example
/* This is a single line comment */
int
main(void)
{
/* Single line comment with code that mandates indenting the comment */
printf("Hello, world!");
return 0;
}
/* Single line comment with no code following it */
Multiline Comments
A multiline comment shall begin with the comment introduction characters on
their own line and end with the comment termination characters on their own
line. Each line between the beginning and ending lines shall begin with the
characters *
aligned with the matching characters in the comment delimeters.
For multiline comments which have no indentation, the characters *
may be
left out of lines within the comment so long as the beginning and ending lines
contain repeating *
characters to fill out the full text width. Text within
this style of comment may start at any column. This type of multiline comment
will be referred to as a "full-width" comment.
A multiline comment shall follow the same indentation rules for a single line comment.
Example
/*
* This is a multiline comment
*/
int
main(void)
{
/*
* A multiline comment indented appropriately
*/
printf("Hello, world!");
return 0;
}
/*******************************************************************************
A multiline comment with no indentation, preceded by repeatings '*'s and
followed by repeating '*'s.
*******************************************************************************/
/*
* A multiline comment with no code following it
*/
File Comments
Each file must begin with the software license inside of its own full-width
comment where each content line is prepended with one tab and no *
character.
Immediately following the software license a new full-width comment will contain
the file name, a blank line, and a short description formatted in the same way
as the software license.
Files which directly correspond to files listed in the ISO/IEC 9899:1990 standard shall use an abbreviated version of the description found in the standard.
Example
/*******************************************************************************
Copyright (c) 2015, Walt Elam
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
/*******************************************************************************
assert.h
Defines the assert macro and refers to another macro, NDEBUG, which is not
defined in this file.
*******************************************************************************/
Function comments
Every function shall be commented. Function prototypes shall not be commented.
A function comment will be in the form of a full-width comment where each line is prepended with a tab. It shall contain the function name, a blank line, a short description, a blank line, function parameters with a short description on their own lines, a blank line, any notes about the function, a blank line, and finally the description of the return value found in the standard followed by special return values and their meanings on their own lines. Parameter lists and return value lists shall be tabularly aligned.
Standard library functions shall use descriptions found in the standard.
Example
/*******************************************************************************
memcmp
The memcmp function compares the first n characters of the object pointed to
by s1 to the first n characters of the object pointed to by s2.
s1 Pointer to the first object being compared
s2 Pointer to the second object being compared
n The number of characters to compare
The memcmp function returns an integer greater than, equal to, or less than
zero, accordingly as the object pointed to by s1 is greater than, equal to,
or less than the object pointed to by s2.
1 s1 is greater than s2 at position 1
0 The objects are equal
-1 s1 is lesser than s2 at position 1
*******************************************************************************/
Variable Comments
Global and static variables shall be commented, but local, non-static, variables shall not be commented.
Implementation Comments
Particularly tricky or important sections of code shall be commented but should not duplicate information which is clearly indicated by the code itself.
Todo Comments
Todo comments shall be used to describe code which is meant only as a temporary
solution or as a note for functionality that should be implemented in the
future. Todo comments shall begin with TODO
followed by parenthesis that
encapsulate the username of the person making the comment, a colon and a space,
and then the comment itself. Todo comments which will cross the text width
boundary should use a multiline comment where the first line contains the
previously indicated information with no trailing space and begin the comment
contents on the following line.
It is not necessary to terminate the contents of a Todo comment with a period if it is only one sentence long.
Example
/* TODO(wrelam): Verify string length before proceeding */
/*
* TODO(wrelam):
* This should really be implemented with dynamic memory allocation rather than
* using space on the stack. The callee should pass in the size as well.
*/
Formatting
Character Encoding
Files should only contain characters that are part of the UTF-8 character set defined by RFC3629. For code which is not implementing locale-specific functionality only the first 128 characters of UTF-8 shall be used, i.e. the characters in the ASCII character set defined by RFC20.
Line Length/Text Width
The maximum length of any one line shall be 80 characters.
Exception
String constants may break this rule so that any substring may be searched for without worrying whether the substring occurs across a line wrap.
Example
/*******************************************************************************
usage
Prints the program's usage statement.
*******************************************************************************/
void
usage(void)
{
printf("Usage: program [--verbose] [--format] -i <input files> -o <output files>\n");
}
Tabs and Spaces
A tab shall consist of four spaces and not an actual tab character.
Indentation
Each level of indentation shall add one tab to the previous level.
Tabular Alignment
Tabular alignment refers to aligning rows of text into columns aligned on tab boundaries. It is used when describing the formatting of groups of items like parameter lists or local variables. Tabular alignment means that each successive column will be placed one tab boundary away from the longest entry in the previous column such that at least one space exists between the longest entry and the following column's data. If every item in a single column are the same length, then a single space shall be used instead of inserting multiple spaces to reach the next tab boundary.
Example
int gCount = 0;
char *gBuf = NULL;
long int gSize = 0;
void
function(
char *inBuf,
size_t inSize,
char *outBuf,
size_t outSize)
{
int i = 0;
size_t sIn = 0;
size_t sOut = 0;
char *tmp = NULL;
...
}
Operator Spacing
Spaces should always be placed on either side of a binary operator, unless the operator is the last character in a line. Unary operators will have no spaces between themselves and the operand to which they are being applied.
Parenthesis
Parenthesis shall be used to explicitly define order of operations unless all operators share the same order of precedence.
Files
Each file shall consist of the following groups, in this order:
- File comment
- Header guards (if applicable)
#include
statements#define
statementsenum
,struct
, andunion
definitions- Type declarations
- Function prototypes
- Function definitions
When no order is provided, #include
statements shall be listed in alphabetical
order and listed in two groups, separated by a blank line: systems headers and
local headers. #define
statements shall be grouped according to their use,
where each group is preceded by a comment describing their purpose. Extra
comments to further clarify an individual statement will be placed on their own
line immediately preceding the statement they describe.
Header Guards
Each header file shall include header guards to prevent multiple inclusion.
Example
#ifndef MY_HEADER_H
#define MY_HEADER_H
...
#endif /* MY_HEADER_H */
Include Statements
Include statements shall have on space between the #include
and the header
name being included. They shall be placed in two groups, separated by a blank
line: system headers and local header. When possible, they should be sorted
alphabetically.
Example
#include <stdio.h>
#include <sys/stat.h>
#include "common.h"
#include "sorting.h"
Define statements
Define statements shall have on space between the #define
and the identifier.
The identifier and replacement-list shall be tabularly aligned. For
replacement-lists which only consist of a single char, integer, or float value,
the replacement-list shall be enclosed in parenthesis. For replacement-lists
which span multiple lines, align the \
s at the column after one space is added
to the longest line in the replacement-list.
Example
#define MAX_SIZE (256)
#define MODULE_NAME "stdio"
#define PRINT_ARRAY(x) do \
{ \
int i = 0; \
for (i = 0; i < sizeof(x)/sizeof(x[0]); i++) \
{ \
printf("%s\n", x[i]); \
} \
} while (0)
Enumeration, Structure, and Union Definitions
All enumerations, structures, and unions shall be defined with file or global
scope and shall use the typedef
storage specifier. The typedef
, enum
or
struct
or union
, and tag shall be placed on the same line, with the opening
brace on the following line. Members and enumeration constants shall be listed
on their own lines, one indentation level in from the enum/structure/union
braces. Member types and names shall be tabularly aligned in structures and
unions, while enumeration constant names, equals signs, and their values shall
be tabularly aligned and include a comma after the last enumeration constant.
Example
typedef struct myStruct
{
unsigned int member1;
long member2;
} MyStruct;
typedef union myUnion
{
unsigned long member1;
unsigned char member2;
} myUnion;
typedef enum color
{
BLUE = 1,
GREEN = 2,
RED = 3,
} Color;
Variable Declarations
A variable declaration shall consist of the following, in order and separated by a single space:
The storage-class specifier shall be stated, one of:
auto
extern
register
static
typedef
If the storage-class specifier is auto, it is optional.
The qualification, if applicable, one of:
const
const volatile
volatile
The type specifier shall be the least verbose version of the corresponding set listed in the standard, one of:
void
signed char
unsigned char
short
unsigned short
int
unsigned int
long
unsigned long
float
double
long double
- struct or union specifier
- enum specifier
- typedef name
char
and an implied int
through the use of no type-specifier shall not
be used.
The storage-class, qualification, and type specifier will collectively be referred to as a variable's type.
Each variable shall be declared on its own line.
Example
typedef unsigned short uint16;
extern long size;
typedef struct memoryBlock
{
unsigned int size;
signed long length;
void *data;
} MemoryBlock;
typedef enum
{
BLUE = 1,
GREEN = 2,
RED = 3,
} Color;
void
function(void)
{
unsigned char c = 0;
short s = 0;
register unsigned int i = 0;
signed long int l = 0L;
static const float f = 0.0F;
volatile double d = 0.0;
static long double ld = 0.0L;
unsigned char *pC = NULL;
unsigned int aScores[10] = { 0 };
...
}
Function Definitions and Prototypes
A function prototype or definition shall not be indented excluding the
parameter list as decribed below. It shall be formatted such that the return
type is placed on a line by itself with the function name and parameters on the
following line. Parameters shall go on the same line as the function name unless
they will extend past the text width or there are more than three parameters. In
these two cases the opening parenthesis of the parameter list shall go on the
same line as the function name and the parameter list shall begin on the
following line. The parameter list shall be indented by one tab and have the
parameter types and names tabularly aligned. Parameters which fit on the same
line as the function name shall have 1 space following each ,
character which
separates the parameters. If a parameter takes no functions then void
shall
take the place of the parameter list.
Function braces shall be placed in the first column. The opening function brace shall be placed on the line immediately following the line which contains the last function parameter. The closing function brace shall be placed on the line immediately following the last statement in the function.
Example
void
abort(void);
int
memcmp(const void *s1, const void *s2, size_t n);
int
qsort(
void *base,
size_t nmemb,
size_t size,
int (*compar)(const void *, const void *))
{
...
}
int
settings(
struct type UserSettings userSettings,
struct type EnvironmentSettings environmentSettings);
Global Variables
Global variables shall have no indentation and will use a single space to separate the type, name, equals sign, and the initialization value. If multiple global variables exist in the same file then the variable types, names, equals signs, and initialization values shall be tabularly aligned.
Local Variables
Local function variables shall be placed at one indentation level in from the function braces. The variable types, names, equals signs, and initilization values shall be tabularly aligned. If only one local variable exists then a single space may be used to separate the variable type, variable name, and equals sign.
All types shall be initialized to a meaningful value, if none exists yet then
they shall be initialized according to the following rules. All integer types
shall be initialized to 0
and 0L
for long
types; all floating types shall
be initialized to 0.0F
; all char types shall be initialized to 0
; all
pointer types shall be initialized to NULL
; all array types shall be
initialized to { 0 }
or memset
to all-bits zero before use; all enumeration
types shall be initialized to 0
; all structure types and union types shall be
uninitialized. Array initialization lists shall include a space after the
opening brace, after each comma, and a space before the closing brace. If an
initialization list extends past the text width then it shall be broken into
segments of 5 elements per line, with the first five being listed on the same
line as the variable name and each following line of elements aligned with the
elements above it.
Example
int
function(char *in, char *out, size_t size)
{
int i = 0;
size_t sIn = 0;
size_t sOut = 0;
char *tmp = NULL;
...
}
int
function2(char *in)
{
int i = 0;
...
}
Pointers
Pointers shall never have a space between the *
or &
and the variable name,
even during declaration/definition (this conforms to the operator spacing rule).
Example
int
function(void)
{
char *buf = NULL;
char c = 0;
char *tmp = NULL;
...
c = *buf;
tmp = &c;
...
}
Function Calls
A function call shall be placed at the current indentation level and written on one line with all arguments separated by a comma and a single space. If there are more than three arguments being passed to the function or the three arguments extend past the text width, the first shall go on the same line and all following arguments shall be placed on their own lines and aligned with the first argument. The terminating parenthesis and semi-colon shall be placed on the same line and immediately after the final argument. When parameters are spread across multiple lines, no space shall follow the separating comma.
Example
int
function(void)
{
...
otherFunction(var1, 5, NULL);
var2 = thisFunction(buf,
bufLen,
outBuf,
outLen);
reallyLongFunctionName(superLongParameterName1,
superLongParameterName2,
superLongParameterName3);
...
}
If, Else If, and Else Statements
If statements shall have a space separating the if
and the opening parenthesis
of the conditional statement. Braces shall always be used to contain the
statements being executed for the condition, even if only one statement
exists. Braces shall be placed at the same indentation level as the if
and
will be placed on their own lines. The conditional statement shall not have
space between itself and the encapsulating parenthesis. If a constant is used in
the comparison then it shall be placed on the left side of the comparison.
When multiple conditional statements are used, the first will go on the same
line as the if
, with all following conditional statements on their own lines
following the first and aligned with the first conditional statement. When no
more than one condition uses a binary operator and no more than three
conditional statements are used, they may all go on the same line. Each
conditional statement using a binary operator will be encapsulated in a set of
parenthesis. The operators which link separate conditional statements will be
placed at the end of the line, with one space separating the closing parenthesis
of the first conditional statement and the logical operator. If conditional
statements need to be nested (e.g. (arg1 && arg2) || (arg3 && arg4)) then each
distinct group shall be formatted as described above with the operator comparing
the two groups going on its own line. Conditional statements shall only be
nested once.
else if
and else
statements shall be placed on their own line at the same
indentation level as the if
statement which they follow.
Example
int
function(void)
{
...
if (3 < argc)
{
printUsage();
exit(1);
}
if (1 == count)
{
...
}
else if (2 == count)
{
...
}
else
{
...
}
if (!pMem || (0 == strlen(msg)))
{
return -1;
}
if (((0 == arg1) &&
(5 <= arg2))
||
(!pSrc && !pDst))
{
...
}
...
}
Switch Statements
Switch statements shall have a space separating the switch
and the opening
parenthesis which encloses the object being switched on. Braces enclosing the
case statements shall be placed on their own lines at the same indentation level
as the switch
. The case
s shall be placed on their own lines and aligned at
the same indentation level as the switch
with no space between the
constant-expression and the colon. The statements being executed for the space
shall be indented by one level. Braces shall not be used to contain the
statements to be executed for a given case. The default case shall be listed
last and contain a break statement. Whenever the same set of statements is to be
executed for multiple cases, each case shall be placed on its own line with a
comment of the form, /* Fallthrough */
, placed on its own line immediately
preceding the first case in the group. Cases shall be listed in alphanumeric
order when possible.
Example
int
function(void)
{
...
switch (input)
{
case 'a':
options |= OPTION_ALL;
break;
case 'r':
options |= OPTION_RECURSIVE;
break;
/* Fallthrough */
case 'V':
case 'v':
options |= OPTION_VERBOSE;
break;
case default:
break;
}
...
}
Loop Statements
For loops shall have a space separating the for
and the opening
parenthesis of the control expressions. Control statements shall have a space
after each semi-colon and no space between the expressions and their enclosing
parenthesis. If the control expressions extend beyong the text-width then each
expression shall be placed on its own line, except for the first which shall be
placed on the same line as the for
. The separating semi-colons shall be placed
on the same line as the control expressions which they terminate. If multiple
statements exist in a single control expression, a space shall follow the comma
which separates them. Braces containing the iteration statements are required
and shall be placed on their own lines at the same indentation level at the
for
.
Do-while loops shall have the do
placed on its own line and braces, which are
required, shall have the opening brace placed on its own line immediately
following the do
. The terminating brace shall be placed on the line
immediately following the last iteration statement. The while
will be placed
on the same line as the terminating brace with a single space on either side of
the while
keyword, followed by the control statement placed in parenthesis and
finally the semi-colon terminating the do-while loop.
While loops shall have a space between the while
and the opening parenthesis
of the control expression. The opening brace shall be placed on its own line
immediately following the line containing the while
and be placed at the same
indentation level of the while
. The closing brace shall be placed on its own
line immediately following the last iteration statement.
Iteration statements shall be placed at one indentation level in from the loop
statement. Control statements for do-while and while loops should be formatted
the same way as if
statements.
Example
int
function(void)
{
...
for (i = 0; i < 5; i++)
{
...
}
do
{
...
} while (i < 5);
while (i < 5)
{
...
}
...
}
Return Statements
Functions which have a non-void return type shall have a single return statement. The return value shall not be wrapped in parenthesis unless the return value is not a constant expression or variable.
A second return statement is allowed for immediately returning if parameter checking fails.
Example
int
function(char *buf, int len)
{
int ret = 0;
if (!buf || (0 == len))
{
return -1;
}
...
return ret;
}
Goto and Label Statements
goto
s and label
s shall not be used.
Example
/* Nothing is here because you shouldn't use goto or label */
Preprocessor Directives
Preprocessor directives shall not be indented and their contents shall be
indented according to the code that precedes it. Nested preprocessor directives
shall indent by one level for each nesting. Each #endif
shall include a
comment on the same line which specifies which #if
it is matched with.
Example
#ifdef WINDOWS
#define DPRINTF(x) OutputDebugString(x)
#else
#define DPRINTF(x) perror(x)
#endif /* WINDOWS */
int
function(char *buf, int len)
{
if (0 == count)
{
#ifdef WINDOWS
OutputDebugString(L"Count was 0\n");
#elif defined LINUX
perror("Count was 0\n");
#endif /* WINDOWS */
}
...
}
Naming
Be descriptive with naming things but don't make the names long.
File Names
File names shall be camel case and a header file shall share the same base name as the .c file to which it belongs.
Example
- myFile.c
- myFile.h
Define Identifiers
Identifiers in a #define
statement shall be written with all capital letters
with underscores separating words.
Example
#define MAX_PATH (256)
Enumeration, Structure, and Union Names
The tag for an enumeration/structure/union shall be camel case and the corresponding typedef identifier shall be the exact same as the tag except that the first letter shall be capitalized.
typedef struct myStruct
{
int member1;
char *pBuf;
} MyStruct;
Function Names
Function names shall be camel case.
Example
int
myFunction(void)
{
...
}
Variable Names
Variables names shall be camel case. Hungarian notation shall be used on variables which are array, global, or pointer types.
Example
int gCount;
int
main(void)
{
int aSizes[10] = { 0 };
char *pBuf = NULL;
char inputChoice = 0;
...
}
Documentation Generation
Javadoc syntax may be used to enable documentation generation. It is not mandatory as not all comments should have documentation generated from them.
Single Line Comments
A single line comment shall be written as described above, with the exception
that the comment shall start with the characters /**
.
Example
/** A single line comment to be included in generated documentation */
Multiline Comments
A multiline comment shall be written as described above, with the exception that
the first line shall be /**
.
Example
/**
* A multiline comment that is intended to be included in generated
* documentation
*/
Full-Width Comments
Full-width comments shall be written as described above, with the exception that the first line shall be written like so, with the last line unchanged:
/***************************************************************************//**
*******************************************************************************/
or, if some portion of the comment is not to be documented then the undocumented
portion shall come before a single line with the characters *//**
on it, with
the documented portion immediately following on the next line.
Example
/***************************************************************************//**
errno.h
Defines macros relating to error reporting conditions.
*******************************************************************************/
/*******************************************************************************
errno.h - not to have documentation generated
*//**
Defines macros relating to error reporting conditions.
*******************************************************************************/
Tags
Any use of tags shall be such that the tag and the information attached to the tag are tabularly aligned. If the information extends past the text width then the information shall be wrapped to the next line and aligned at the same level of indentation as the first character of that string of information.
Example
/***************************************************************************//**
@file errno.h
@brief Defines macros relating to error reporting conditions.
*******************************************************************************/
/*******************************************************************************
memcmp
*//**
@brief The memcmp function compares the first n characters of the object
pointed to by s1 to the first n characters of the object pointed to
by s2.
@param s1 Pointer to the first object being compared
@param s2 Pointer to the second object being compared
@param n The number of characters to compare
@return The memcmp function returns an integer greater than, equal to, or
less than zero, accordingly as the object pointed to by s1 is
greater than, equal to, or less than the object pointed to by s2.
@retval 1 s1 is greater than s2 at position 1
@retval 0 The objects are equal
@retval -1 s1 is lesser than s2 at position 1
*******************************************************************************/