C Coding Standard
C Coding Standard
C Coding Standard
html
C Coding Standard
Adapted from http://www.possibility.com/Cpp/CppCodingStandard.html and NetBSD's style
guidelines
Contents
1. Names
(important recommendations below)
Include Units in Names
Structure Names
C File Extensions
(other suggestions below)
Make Names Fit
Variable Names on the Stack
Pointer Variables
Global Constants
Enum Names
#define and Macro Names
2. Formatting
(important recommendations below)
Brace {} Policy
Parens () with Key Words and Functions Policy
A Line Should Not Exceed 78 Characters
If Then Else Formatting
switch Formatting
Use of goto,continue,break and ?:
(other suggestions below)
One Statement Per Line
3. Documentation
(important recommendations below)
Comments Should Tell a Story
Document Decisions
Use Headers
Make Gotchas Explicit
Commenting function declarations
(other suggestions below)
Include Statement Documentation
4. Complexity Management
Layering
5. Miscellaneous
1 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
Names
A name is the result of a long deep thought process about the ecology it lives in. Only a programmer who
understands the system as a whole can create a name that "fits" with the system. If the name is appropriate
everything fits together naturally, relationships are clear, meaning is derivable, and reasoning from common
human expectations works as expected.
If you find all your names could be Thing and DoIt then you should probably revisit your design.
Function Names
Usually every function performs an action, so the name should make clear what it does:
check_for_errors() instead of error_check(), dump_data_to_file() instead of data_file(). This will also
make functions and data objects more distinguishable.
Structs are often nouns. By making function names verbs and following other naming conventions
programs can be read more naturally.
2 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
For example: retry_max to mean the maximum number of retries, retry_cnt to mean the current retry
count.
Structure Names
Use underbars ('_') to separate name components
When declaring variables in structures, declare them organized by use in a manner to attempt to
minimize memory wastage because of compiler alignment issues, then by size, and then by
alphabetical order. E.g, don't use ``int a; char *b; int c; char *d''; use ``int a; int b; char *c; char *d''.
Each variable gets its own type and line, although an exception can be made when declaring bitfields
(to clarify that it's part of the one bitfield). Note that the use of bitfields in general is discouraged.
Major structures should be declared at the top of the file in which they are used, or in separate header
files, if they are used in multiple source files. Use of the structures should be by separate declarations
and should be "extern" if they are declared in a header file. It may be useful to use a meaningful prefix
for each member name. E.g, for ``struct softc'' the prefix could be ``sc_''.
Example
struct foo {
struct foo *next; /* List of active foo */
struct mumble amumble; /* Comment for mumble */
int bar;
unsigned int baz:1, /* Bitfield; line up entries if desired */
fuz:5,
zap:2;
uint8_t flag;
};
struct foo *foohead; /* Head of global foo list */
3 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
Justification
With this approach the scope of the variable is clear in the code.
Now all variables look different and are identifiable in the code.
Example
Pointer Variables
place the * close to the variable name not pointer type
Example
char *name= NULL;
Global Variables
Global variables should be prepended with a 'g_'.
Global variables should be avoided whenever possible.
Justification
Example
Logger g_log;
Logger* g_plog;
Global Constants
4 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
Justification
It's tradition for global constants to named this way. You must be careful to not conflict with other global
#defines and enum labels.
Example
const int A_GLOBAL_CONSTANT= 5;
Justification
This makes it very clear that the value is not alterable and in the case of macros, makes it clear that you are
using a construct that requires care.
Some subtle errors can occur when macro names and enum labels use the same name.
Example
#define MAX(a,b) blah
#define IS_ERR(err) blah
#define MACRO(v, w, x, y) \
do { \
v = (x) + (y); \
w = (y) + 2; \
} while (0)
Enum Names
Labels All Upper Case with '_' Word Separators
This is the standard rule for enum labels. No comma on the last element.
Example
enum PinStateType {
PIN_OFF,
5 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
PIN_ON
};
It's often useful to be able to say an enum is not in any of its valid states. Make a label for an uninitialized or
error state. Make it the first label if possible.
Example
Formatting
Brace Placement
Of the three major brace placement strategies one is recommended:
All if, while and do statements require braces even if there is only a single statement within the braces. For
example:
if (1 == somevalue) {
somevalue = 2;
}
Justification
It ensures that when someone adds a line of code later there are already braces and they don't forget. It
provides a more consistent look. This doesn't affect execution speed. It's easy to do.
Justification
6 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
It provides safety when adding new lines while maintainng a compact readable form.
} /* if valid */
else {
} /* not valid */
} /* end forever */
Justification
Keywords are not functions. By putting parens next to keywords keywords and function names are
made to look alike.
Example
if (condition) {
}
while (condition) {
}
strcpy(s, s1);
return 1;
7 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
Justification
Even though with big monitors we stretch windows wide our printers can only print so wide. And we
still need to print code.
The wider the window the fewer windows we can have on a screen. More windows is better than wider
windows.
We even view and print diff output correctly on all terminals and printers.
It's up to the programmer. Different bracing styles will yield slightly different looks. One common approach
is:
if (condition) {
} else if (condition) {
} else {
}
If you have else if statements then it is usually a good idea to always have an else block for finding unhandled
cases. Maybe put a log message in the else even if there is no corrective action taken.
Condition Format
Always put the constant on the left hand side of an equality/inequality comparison. For example:
if ( 6 == errorNum ) ...
One reason is that if you leave out one of the = signs, the compiler will find the error for you. A second
reason is that it puts the value you are looking for right up front where you can find it instead of buried at the
end of your expression. It takes a little time to get used to this format, but then it really gets useful.
switch Formatting
Falling through a case statement into the next case statement shall be permitted as long as a comment is
included.
The default case should always be present and trigger an error if it should not be reached, yet is
reached.
If you need to create variables put all the code in a block.
Example
switch (...)
{
case 1:
...
/* comments */
8 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
case 2:
{
int v;
...
}
break;
default:
}
Goto statements should be used sparingly, as in any well-structured code. The goto debates are boring so we
won't go into them here. The main place where they can be usefully employed is to break out of several levels
of switch, for, and while nesting, although the need to do such a thing may indicate that the inner constructs
should be broken out into a separate function, with a success/failure return code.
for (...) {
while (...) {
...
if (disaster) {
goto error;
}
}
}
...
error:
clean up the mess
When a goto is necessary the accompanying label should be alone on a line and to the left of the code that
follows. The goto should be commented (possibly in the block header) as to its utility and purpose.
Continue and break are really disguised gotos so they are covered here.
Continue and break like goto should be used sparingly as they are magic in code. With a simple spell the
reader is beamed to god knows where for some usually undocumented reason.
while (TRUE) {
...
/* A lot of code */
9 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
...
if (/* some condition */) {
continue;
}
...
/* A lot of code */
...
if ( i++ > STOP_VALUE) break;
}
Note: "A lot of code" is necessary in order that the problem cannot be caught easily by the programmer.
From the above example, a further rule may be given: Mixing continue with break in the same loop is a sure
way to disaster.
?:
The trouble is people usually try and stuff too much code in between the ? and :. Here are a couple of clarity
rules to follow:
Example
(condition) ? funct1() : func2();
or
(condition)
? long statement
: another long statement;
1. The code is easier to read. Use some white space too. Nothing better than to read code that is one line
after another with no white space or comments.
Do:
char **a = 0; /* add doc */
char *x = 0; /* add doc */
10 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
In general enums are preferred to #define as enums are understood by the debugger.
Be aware enums are not of a guaranteed size. So if you have a type that can take a known range of values and
it is transported in a message you can't use an enum as the type. Use the correct integer size and use constants
or #define. Casting between integers and enums is very error prone as you could cast a value not in the enum.
Macros
Don't Turn C into Pascal
Don't change syntax via macro substitution. It makes the program unintelligible to all but the perpetrator.
Example
11 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
#define MAX(x,y) (((x) > (y) ? (x) : (y)) // Get the maximum
The macro above can be replaced for integers with the following inline function with no loss of efficiency:
inline int
max(int x, int y) {
return (x > y ? x : y);
}
Example
MAX(f(x),z++);
Example
#define ADD(x,y) x + y
must be written as
Justification
More problems than you can believe are eventually traced back to a pointer or variable left
uninitialized.
12 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
Short Functions
Functions should limit themselves to a single page of code.
Justification
The idea is that the each method represents a technique for achieving a single objective.
Most arguments of inefficiency turn out to be false in the long run.
True function calls are slower than not, but there needs to a thought out decision (see premature
optimization).
{
;
if (FAIL != f())
is better than
if (f())
even though FAIL may have the value 0 which C considers to be false. An explicit test will help you out later
when somebody decides that a failure return should be -1 instead of 0. Explicit comparison should be used
even if the comparison value will never change; e.g., if (!(bufsize % sizeof(int))) should be written instead as
if ((bufsize % sizeof(int)) == 0) to reflect the numeric (not boolean) nature of the test. A frequent trouble
spot is using strcmp to test for string equality, where the result should never ever be defaulted. The preferred
approach is to define a macro STREQ.
13 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
inline bool
string_equal(char* a, char* b)
{
(strcmp(a, b) == 0) ? return true : return false;
Or more compactly:
return (strcmp(a, b) == 0);
}
Note, this is just an example, you should really use the standard library string type for doing the comparison.
The non-zero test is often defaulted for predicates and other functions or expressions which meet the
following restrictions:
The ++ and -- operators count as assignment statements. So, for many purposes, do functions with side
effects. Using embedded assignment statements to improve run-time performance is also possible. However,
one should consider the tradeoff between increased speed and decreased maintainability that results when
embedded assignments are used in artificial places. For example,
a = b + c;
d = a + r;
d = (a = b + c) + r;
even though the latter may save one cycle. In the long run the time difference between the two will decrease
as the optimizer gains maturity, while the difference in ease of maintenance will increase as the human
memory of what's going on in the latter piece of code begins to fade.
Documentation
14 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
Document Decisions
Comments should document decisions. At every point where you had a choice of what to do place a comment
describing which choice you made and why. Archeologists will find this the most useful information.
Use Headers
Use a document extraction system like Doxygen.
These headers are structured in such a way as they can be parsed and extracted. They are not useless like
normal headers. So take time to fill them out. If you do it right once no more documentation may be
necessary.
Comment Layout
Each part of the project has a specific comment layout. Doxygen has the recommended format for the
comment layouts.
Gotcha Keywords
@author:
specifies the author of the module
@version:
specifies the version of the module
@param:
specifies a parameter into a function
@return:
15 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
@deprecated:
says that a function is not to be used anymore
@see:
creates a link in the documentation to the file/function/variable to consult to get a better understanding
on what the current block of code does.
@todo:
what remains to be done
@bug:
report a bug found in the piece of code
Gotcha Formatting
16 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
Layering
Layering is the primary technique for reducing complexity in a system. A system should be divided into
layers. Layers should communicate between adjacent layers using well defined interfaces. When a layer uses
a non-adjacent layer then a layering violation has occurred.
A layering violation simply means we have dependency between layers that is not controlled by a well
defined interface. When one of the layers changes code could break. We don't want code to break so we want
layers to work only with other adjacent layers.
Sometimes we need to jump layers for performance reasons. This is fine, but we should know we are doing it
and document appropriately.
Miscellaneous
General advice
This section contains some miscellaneous do's and don'ts.
Don't use floating-point variables where discrete values are needed. Using a float for a loop counter is a
great way to shoot yourself in the foot. Always test floating-point numbers as <= or >=, never use an
exact comparison (== or !=).
Compilers have bugs. Common trouble spots include structure assignment and bit fields. You cannot
generally predict which bugs a compiler has. You could write a program that avoids all constructs that
are known broken on all compilers. You won't be able to write anything useful, you might still
encounter bugs, and the compiler might get fixed in the meanwhile. Thus, you should write ``around''
compiler bugs only when you are forced to use a particular buggy compiler.
Do not rely on automatic beautifiers. The main person who benefits from good program style is the
programmer him/herself, and especially in the early design of handwritten algorithms or pseudo-code.
Automatic beautifiers can only be applied to complete, syntactically correct programs and hence are
not available when the need for attention to white space and indentation is greatest. Programmers can
do a better job of making clear the complete visual layout of a function or file, with the normal
attention to detail of a careful programmer (in other words, some of the visual layout is dictated by
intent rather than syntax and beautifiers cannot read minds). Sloppy programmers should learn to be
careful programmers instead of relying on a beautifier to make their code readable. Finally, since
beautifiers are non-trivial programs that must parse the source, a sophisticated beautifier is not worth
the benefits gained by such a program. Beautifiers are best for gross formatting of machine-generated
code.
Accidental omission of the second ``='' of the logical compare is a problem. The following is confusing
and prone to error.
17 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
Does the programmer really mean assignment here? Often yes, but usually no. The solution is to just
not do it, an inverse Nike philosophy. Instead use explicit tests and avoid assignment with an implicit
test. The recommended form is to do the assignment before doing the test:
abool= bbool;
if (abool) { ... }
Modern compilers will put variables in registers automatically. Use the register sparingly to indicate
the variables that you think are most critical. In extreme cases, mark the 2-4 most critical values as
register and mark the rest as REGISTER. The latter can be #defined to register on those machines with
many registers.
Be Const Correct
C provides the const key word to allow passing as parameters objects that cannot change to indicate when a
method doesn't modify its object. Using const in all the right places is called "const correctness." It's hard at
first, but using const really tightens up your coding style. Const correctness grows on you.
Someone else might compile the code with turned-of debug info like:
cc -c lurker.cc -DDEBUG=0
Alway use #if, if you have to use the preprocessor. This works fine, and does the right thing, even if DEBUG
is not defined at all (!)
#if DEBUG
temporary_debugger_break();
#endif
If you really need to test whether a symbol is defined or not, test it with the defined() construct, which allows
you to add more things later to the conditional without editing text that's already in the program:
#if !defined(USER_NAME)
#define USER_NAME "john smith"
#endif
18 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
Using #if 0
#if 0
lots of code
#endif
more code
}
You can't use /**/ style comments because comments can't contain comments and surely a large block of your
code will contain a comment, won't it?
Don't use #ifdef as someone can unknowingly trigger ifdefs from the compiler command line. #if 0is that
even day later you or anyone else has know idea why this code is commented out. Is it because a feature has
been dropped? Is it because it was buggy? It didn't compile? Can it be added back? It's a mystery.
#if OBSOLETE
#if TEMP_DISABLED
Add a short comment explaining why it is not implemented, obsolete or temporarily disabled.
File Extensions
In short: Use the .h extension for header files and .c for source files.
19 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
1. It's bad magic to have space consuming code silently inserted through the innocent use of header files.
2. It's not common practice to define variables in the header file so it will not occur to developers to look
for this when there are problems.
3. Consider defining the variable once in a .c file and use an extern statement to reference it.
If you have code that must compile in a C and C++ environment then you must use the __cplusplus
preprocessor directive. For example:
#ifdef __cplusplus
#else
extern some_function();
#endif
No Magic Numbers
A magic number is a bare naked number used in source code. It's magic because no-one has a clue what it
means including the author inside 3 months. For example:
20 of 21 4/27/2018, 10:16 AM
C Coding Standard https://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
In the above example what do 22 and 19 mean? If there was a number change or the numbers were just plain
wrong how would you know? Instead of magic numbers use a real name that means something. You can use
#define or constants or enums as names. Which one is a design choice. For example:
#define PRESIDENT_WENT_CRAZY (22)
const int WE_GOOFED= 19;
enum {
THEY_DIDNT_PAY= 16
};
Now isn't that better? The const and enum options are preferable because when debugging the debugger has
enough information to display both the value and the label. The #define option just shows up as a number in
the debugger which is very inconvenient. The const option has the downside of allocating memory. Only you
know if this matters for your application.
21 of 21 4/27/2018, 10:16 AM