-
Notifications
You must be signed in to change notification settings - Fork 10
StyleGuide Statements
Make your statements clear and distinct. Do not become a contender for the Obfuscated C Code Contest.
The comma operator often camouflages clear intent from the human eye.
Each line should only contain one statement.
For example:
{
argv++;
argc--;
}
Not:
{
argv++; argc--; // Bad
}
A statement block is a list of statements enclosed in braces.
The enclosed statements must be indented one more level than the enclosing compound statement. The opening brace is at the end of the line that begins the statement block; the closing brace begins a line and is indented to same level as the brace beginning the statement block.
For example:
{
for (int i = 0; i < 10; i++) {
...
}
{
// A statement block.
...
}
}
Many times functions will be defined as returning int
and yet overload a return value with NULL
or zero to indicate a failure.
Do not conflate the value zero or NULL
with false in a conditional.
Be explicit about the value.
For example, this:
if (strcmp(stringA, stringB) == 0) {
printf("Equal!\n");
}
Not this:
if (!strcmp(stringA, stringB)) {
printf("Equal!\n");
}
Typically a goto
statement is used to impose structure on code at runtime,
rather than addressing structure through design.
Instead, invest the time in designing the code to avoid jumping around.
The if-else class of statements has the following form:
if (condition) {
..
}
if (condition) {
...
} else {
...
}
if (condition) {
...
} else if condition) {
...
} else {
...
}
If statements should never be of the error-prone form:
if (condition)
...;
If you must write a long if
statement,
organize the line wrapping to illustrate groups of like terms.
Indent the lines two levels of indentation to avoid making them look like the
body of the if statement.
For example, the indentation below inappropriately requires the reader to properly parse the grouping visually:
if ((condition1 && condition2)
|| (condition3 && condition4)
||!(condition5 && condition6)) {
doSomethingAboutIt();
}
Instead use a format like this:
if ((condition1 && condition2)
|| (condition3 && condition4)
|| !(condition5 && condition6)) {
doSomethingAboutIt();
}
It is best to not rely on side-effects as the result of a logical operation.
In addition to detracting from clarity, the right-hand side of the &&
and
||
operators are not evaluated if the left-hand
side is sufficient to determine the logical value,
therefore, the side-effects may not even be what you expect.
A for
statement has the following form:
for (initialization; condition; update) {
...
}
An empty for
statement
(one in which all the work is done in the initialization, condition, and update clauses)
has the following form:
for (initialization; condition; update) {
// empty
}
Avoid using the comma operator within the update clause of a for
statement.
for (int i = 0; i < 10; i++, p++) {
// empty
}
Be clear and make it the body of the for
statement:
for (int i = 0; i < 10; i++) {
p++;
}
If a for
loop iterator has no scope outside of the for
loop,
declare the variable in the for
loop initializer.
for (int i = 10; i > 0; i--) {
...
}
A while statement has the following form:
while (condition) {
...
}
An empty while statement has the following form:
while (condition) {
// empty
}
A do-while statement has the following form:
do {
...
} while (condition);
A switch statement has the following form:
switch (condition) {
case ABC:
...
// falls through
case EF:
...
break;
case XYZ: {
...
break;
}
default:
...
break;
}
Every time a case falls through (i.e. it doesn't include a break statement),
add a comment where the break
statement would normally be to show the intent
and not that you just forgot the break
statement.
This is shown in the preceding code example with the // falls through
comment.
Every switch statement must include a default case.
The break in the example default:
case is redundant as it is the
last case in the switch
statement,
but it prevents a fall-through error if another case is added later.
A return statement with a value should not use parentheses unless they are necessary for proper evaluation, or make the return value more obvious and distinct.
For example:
return;
return result;
return (size + 2) / 3;
Keep ternary statements simple and don't them as substitutes for nested if-else statements.
For ternary expressions that cannot fit on one line,
break before the ?
and :
operators.
alpha = (aLongBooleanExpression) ? beta : gamma;
alpha = (aLongBooleanExpression) ? beta
: gamma;
alpha = (aLongBooleanExpression)
? beta
: gamma;
Variable name should be nouns.
There is one constant or variable declaration per line.
Variables and constants should be initialized in their declarations as in:
char *p = "Hello World";
If at all possible, avoid using floating point arithmetic, particularly in loops or where precision is necessary.
Use the double type instead.
Avoid C89 variable declarations, and simply declare variables as close as possible to where they are used. This saves the reader from having to remember the declaration of a variable prior to its use. For example, avoid this style of declaring variables:
{
int i;
char *p;
bool done;
for (i = 10; i > 0; i--) {
...
}
p = NULL;
done = true;
}
Instead, reformat to declare the variables where they are used:
{
for (int i = 10; i > 0; i--) {
...
}
char *p = NULL;
bool done = true;
}
Avoid allocating memory and use the C99 dynamic array allocation where possible.
For example:
int size = atoi("10");
char array[size];
Instead of the archaic method:
int size = atoi("10");
char *array = calloc(sizeof(char), size);
...
free(array);