What is a Coding Style?
For some people, a coding style document may be a new thing. This section is for those of you that are the lucky one in ten thousand (relevant XKCD ). For those of you that are familiar with one, but are questioning why a coding style document is a good thing to have, skip to the next section (click here to skip). If you wish to just skip straight to the content of my style, click here. For everyone else, I hope that this post helps you to understand both what a coding style document is and why having one is a good idea for many different types of projects.
A coding style is a document, or set of documents, that describes how code is to be formatted and styled. Frequently, a coding style does not cover everything involved with writing code, leaving some of the style up to the individual programmer. Things that may be commonly added to a coding style are:
- Naming guidelines for member variables, functions, and types.
- Naming guidelines for global functions, variables, and types.
- Guidelines for how the
{}
braces should be placed for function definitions, conditionals, etc. - How namespaces and global variables should be used, or when they should be used.
- Tabs versus spaces.
- And much more.
There may be multiple coding style documents at one place for different programming languages (e.g. one for Python, one for C++, one for Lua, etc.) As each language has its own unique properties, though, some languages may share properties with one or more. Every different style will most likely be based off of either the current best practices for the language or the style used historically at a company.
This is just a basic overview of what a coding style is, as there can be a lot more in a coding style (e.g. see the SEI C++ coding style as an example). Hopefully you have a better understanding of what a coding style is after reading this section.
Why Have a Coding Style?
A coding style is not something that is meant for just one person, it is a way that any individual or group can help communicate their code. Commenting code (there is a debate that code should be a comment for itself, but that is for another time) is one way of communicating what your code does, but having a consistent style can also help as well.
Having a consistent style can not only help communicate what your code does, but also make it clearer as to how it does what it does. A coding style helps differentiate between parts of code, standardizing it in a way that someone who knows the style can pick up where previous individuals left off pretty quickly.
Everyone writes code in a different style, as it is either how they were trained by their integrated development environment (IDE) or they discovered what they thought was more readable in a more basic text editor. The styles of every individual are personal, and can lead to lengthy arguments about the “correct” way to format code. This is probably one of the most important reasons to have a coding style, as a coding style standardizes the way that code is formatted. With a standardized format, no lengthy arguments will get in the way of programming (this is not guaranteed, as people may argue about it during lunches).
There are many more reasons to have a coding style for individual projects or a company as a whole. Too many, in fact, for me to cover in this post. However, hopefully these reasons are enough to whet your interest in learning more about different coding styles!
My Style
Here we are at last to the meat of this post! This coding style is the one that I will use for all of the C and C++ code on this blog (I may produce another coding style post if I ever end up using another language on here other than C or C++). This will not be an all-encompassing document, as there will be things that differ from post to post, unless they have been stated here. With all that having been said, here is the coding style for this blog:
Portable Aliases for Basic Types
The type aliases are:
bool
for boolean values (size should never be assumed).uint8
for unsigned 8-bit integers (1 byte).uint16
for unsigned 16-bit integers (2 bytes).uint32
for unsigned 32-bit integers (4 bytes).uint64
for unsigned 64-bit integers (quad words) (8 bytes).int8
for signed 8-bit integers (1 byte).int16
for signed 16-bit integers (2 bytes).int32
for signed 32-bit integers (4 bytes).int64
for signed 64-bit integers (quad words) (8 bytes).float32
for single precision floating point (4 bytes).float64
for double precision floating point (8 bytes).intptr
for an integer that can hold a pointer (size should never be assumed).cchar
for a character (size should never be assumed).
For use with the cchar
type: to create a string literal (a C-string), the CAL_STR( )
macro should be used with the string literal. This will convert the string literal to the type that cchar
is typed to.
Naming Conventions
There are quite a few things that are shared between the various parts of code that are named, such as types and variables. However, instead of creating a generic convention for the shared parts of how they are named, parts of the style will be repeated.
Namespaces
- The primary namespace for all code (that has namespaces) will be named cal.
- All other namespaces do not have any naming requirements.
Macros/Defines
- All macros and defines will be in all uppercase lettering.
- An underscore will be present between words, in order to differentiate between them.
- All macros and defines will be prefixed with “CAL_".
Types
- The first letter of each word in a name is capitalized.
- There are no underscores between words in a name.
- Interfaces that only define a type, but have no implementation, are prefixed with I.
- Types that only define data, such as a
struct
type, shall betypedef
'd (for support in both C and C++) and prefixed with D. - Enumerations (
enum
orenum class
) shall be bothtypedef
'd (for support in both C and C++) and prefixed with E. - All other types will be prefixed with N.
- Template classes are prefixed with T.
- Typedefs of a templated type are no longer considered a template type and shall be prefixed with N.
- All type names shall be nouns.
- Types that only contain static functions and variables shall have no prefix.
If a struct
type is not a simple piece of data, or is unusable in the C programming language, it follows the naming rules of a class
type.
Type Examples
Good:
// This is good because the C++ way of declaring variable
// will be valid in C the way this struct is declared and
// typedef'd.
typedef struct
{
// Some data types here
} DTea;
// It can be used like this in both C and C++:
DTea Tea;
// In this instance, because it is not a usable type in
// C, this is correct. It follows the rules of a templated
// class here.
template<typename InType>
struct TRemoveConst
{
// Code here.
};
class NWindow
{
// code here
};
// Which can be used like this in C++:
NWindow Window;
Bad:
// This is bad because it cannot be utilized in C as
// easily as it can in C++.
struct DTea
{
// Some data types here
};
// In C++, this is how it can be used
// (this has not changed from the 'good' version):
DTea Tea;
// In C, it would need to be used like so:
struct DTea Tea; // Quite the difference!
Variables
- Global variables are prefixed with G.
- Member variables are prefixed with M, unless it is a boolean value.
- Boolean values will be prefixed with b.
- The first letter of each word in a name is capitalized.
- There are no underscores between words in a name.
- All variable names shall be nouns.
- Function parameters have no prefix, with the exception of boolean values.
In the case where a function parameter is a reference whose value is expected to be changed, the parameter should be prefixed with “Out”. If that parameter is a boolean variable, it should still be prefixed with “b” before either an “In”/“Out” prefix (e.g. bOutWasTransferSuccessful
).
Variables should be declared one at a time so that a comment can be provided for the meaning of the variable. Multi-line or single line comments before a comment are acceptable.
Variable Examples
Good:
DTea GTea;
bool bTeaIsWarm;
int32 MTeacupSize;
int32 ElementCount;
Bad:
DTea g_Tea;
DTea tea;
bool teaIsWarm;
bool b_teaIsWarm;
int32 m_teacup_size;
Functions
- In the case where
namespace
is not available, all functions in the global namespace will be prefixed with cal. - The first letter of each word in a name is capitalized.
- There are no underscores between words in a name.
- Function names are verbs that describe the functions effect, or the return value of a function that has no effect.
- Function names should be clear, descriptive, and unambiguous. Over-abbreviation should be avoided.
Functions that return a boolean value should ask a true or false question.
Procedure (functions that return no value) names should use a strong verb followed by an object. One exception to this, is if the object being referred to is the object containing the procedure.
Function Examples
Good:
bool HasAllocation( ) const;
void ActivatePhoton( );
int32 GetElementCount( ) const;
DTea calPourTea( );
Bad:
bool allocation( ) const;
void activate_photon( );
int32 getElementCount( ) const;
Comments
Comments in the code will be directly explaining the code only if needed. In this case, they are an extra tool for communication as the blog itself will provide the bulk of the explaining.
Braces
The {}
braces will always be on their own line.
Examples
// Correct
if( bTeaIsWarm )
{
// Do something here.
}
// Incorrect
if( bTeaIsWarm ){
// NOT CORRECT.
}
// Correct
for( ; true; )
{
// Do something here.
}
// Incorrect
for( ; true; ){
// NOT CORRECT.
}
If – Else
All blocks of execution should be contained inside of a pair of braces when inside of an if-else statement. Mistakes in the code are frequently produced when braces are not present in if-else statements, so this is a preventative measure.
Examples
Some good examples:
if( bTeaIsWarm )
{
PourTea( );
}
if( bPhasersReady )
{
FirePhasers( );
}
else
{
PowerPhasers( );
}
Enums
This is only applicable to C++
All enum
s will be either contained in a namespace or in an enum class
. This is to prevent the clutter of the global namespace and to allow different enums to have similarly named values. As this is specific to C++, a typedef
of the enum
type is not required.
Examples
Some good examples:
namespace EWindowMode
{
enum Type
{
// enum values here
};
} // namespace EWindowMode
enum class EErrorCode
{
// enum values here
};
Tabs VS Spaces
Because of the difference in browsers that may render this blog, in order to get a consistent spacing, spaces will be used in all code instead of tabs.
Afterword
This is the standard that I will use for all C and C++ code that finds its way to this blog or one of the git repositories that this blog will have. This is not an all-encompassing coding style, as there are many parts of code that are not included. This may be updated in the future.
The code used in the portable aliases can be found here .