-
Notifications
You must be signed in to change notification settings - Fork 26
Coding standard
This standard is designed to give general style recommendations to ease everybody's work in the Fibernavigator. Some rules are very abstract and relate to general points. Other rules are more specific and apply to specific parts of the coding process.
We expect you to follow this standard. Of course, since the standard was added after more than 1000 commits to the repository, there is some code not following exactly this standard, even if it was modeled to fit with the existing style. If you find such code, please adjust it, if it doesn't involve weeks of work.
Some points are marked as MANDATORY, which indicates that the programer really should do his best to conform to the standard. Other elements are marked as SUGGESTION, which indicates that, if possible, this rule should be followed, but it is not mandatory. An example of such a rule is the placement of curly brackets. If you add code to a file already following a different standard on the placement of the brackets, use the existing standard instead. If you create a new file, try to use this standard.
The most important point here is to use the same coding style throughout a file, and throughout a class. Even if it is not the official standard, at least a new coder will be able to orient himself if the coding style of the file / class is homogeneous.
Summary of sections
- Introduction
-
Naming Conventions
- Class names
- Method names
- Method argument names
- Class attribute names (data members)
- Variable names on the stack
- Pointer variables
- Global definitions (defines)
- Global constants
- Static variables
- Type names
- Enumeration names and labels
- Variables representing a collection of entities
- C++ file names and extensions
- Internal file organization
- Code formatting guidelines
- Credits
The names used in the code should fit in the code, they should represent the named entity. That way, any programer will be able to easily grasp the purpose of the named entity.
If a variable represents time, weight, or some other unit, then includes the unit in the name so that other developers can more easily spot problems. For example :
int timeOutMs // More explicit than timeOut. int weightLbs // More explicit than weight.
- Name the class after what it is.
- Do not use the parent class's name in the derived class's name.
- Suffixes are something helpful. For example, if your system uses agents then naming something “DynamicAgent” conveys real information.
- Use upper case letters as word separators, lower case for the rest of a word. (Pascal case)
- First character in a name is upper case.
- No underscore (_).
class NameOneTwo class Name
- Start the name with a verb, since a method / function normally executes an action.
- Suffixes are sometimes useful :
- Max – To mean the maximum values something can have.
- Cnt – The current count of a running count variable.
- Key – Key value.
- Prefixes are sometimes useful :
- is – To ask a question about something, for example: isInitialized()
- get – To get a value, for example: getIterationCnt()
- set – To set a value, for example: setIterationCnt()
- Use the same rules as for class names, except that the names should start with a lower case letter.
class NameOneTwo { public: int execute(); void handleError(); };
- Follow the same rules as variables on the stack
class NameOneTwo { public: int startYourEngines(Engine& someEngine, Engine& anotherEngine); }
- Attribute names should be preceded by “m_”. (small caps)
- After the “m_”, use the same rules as for class names, except that the first letter will be lower case.
- ‘m’ always precedes other name modifiers.
class NameOneTwo { public: int getVarAbc(); int getErrorNumber(); private: int m_varAbc; int m_errorNumber; String* m_pName; }
- No special prefix should be used for local variables, since all other variables and members type have a prefix.
- The first word should be lower case.
- All following words should begin with an upper case character.
int NameOneTwo::handleError( int i_errorNumber ) { int errorId = OsErr(); Time timeOfError; ErrorProcessor errorProcessor; Time* pOutTime = 0; }
- Pointer variables should be preceded by a "p".
- Place the * close to the pointer type, not the variable name.
String* pName = new String; String* pFullName, address; // Note: only pFullName is a pointer.
- Should be all caps with "_" separators between words.
#define GLOBAL_CONSTANT 5;
- First letter of each word is a capital letter.
- Each word is separated by an underscore "_".
const int Global_Variable_Which_Is_Const
- For the moment, there are no specific rules for static variables.
- When possible for types based on native types, make a typedef. (This only applies to values/types that are accessible outside of a given class.)
- Typedef names should use the same naming policy as for a class.
typedef short int ModuleIdentifier; typedef int VectorIterator;
- Enumeration names follow the same rule as class names.
- All words in the enum are upper case.
- Refrain from using the plural to name an enumeration. For example, DisplayShape instead of DisplayShapes.
enum DisplayShape { NORMAL, SPHERE, AXES, AXIS };
- A variable representing a collection of entities should end with an "s" to represent the fact that multiple objects may be stored in it.
std::vector< Character > m_characters; // Multiple characters. Character m_mainCharacter; // One character.
- Header files have the extension “.h”
- Source files have the extension “.cpp”
- Templated class implementation should be contained in a secondary file, having the extension “.hpp”. The .hpp file should be located in the same folder as the .h file and be included directly at the end of the header declaration in the .h file.
- .h and .cpp files should be named after the class they contain. For example, files that declares and implements the class “DynamicAgent” should be named “DynamicAgent.h” and “DynamicAgent.cpp”.
- Header files will usually contain the declaration of a single class, or multiple small classes that are tightly coupled or related.
- The last line of the file should always be a blank line. This is required by some compilers.
- Header files should always contain multiple inclusion guards, sporting the following format :
#ifndef FILENAME_H_ #define FILENAME_H_ //{… file content …} #endif //FILENAME_H_ // This line should be blank, but it doesn't show here.
To facilitate the reading and organizing of the #include section, the include instructions should be in the following order:
- Start with the header of your file. Ex: In MyClass.cpp, the first include should be #include "MyClass.h"
- Add files from the same directory in alphabetical order.
- Add files in the same project from other folders, listed in alphabetical order.
- Add files from project-specific librairies, for example, wxWidgets.
- Add files from generic librairies, for example, <iostream>.
Also, if you are using types defined in a namespace, you should add your usings under your include.
Example:
#include "MyClass.h" #include "AnotherClass.h" #include "SomeClass.h" #include "A_Folder/SomeOtherClass.h" #include <GL/glew.h> #include <wx/string.h> #include <iostream> using std::cout; using std::endl;
A common class layout is critical from a code comprehension point of view and for automatically generating documentation from the code.
The access levels for class members should be defined in the class declaration in the following order:
- public
- protected
- private
Public section
Only put an object’s interface in the public section. DO NOT expose any private data items in the public section. At least encapsulate access via access methods (get/set). Ideally, your method interface should make most access methods unnecessary. Do not put data in the public interface.
Protected section
The protected section should contain any data or method that could be needed by a children class through inheritance to properly expand upon the parent class and utilize its abstract concepts.
Private section
The private section should contain any data or method that must not be modified by children classes, such that their improper usage or modification would prevent parent classes from working.
- Constructors should be placed at the beginning of the public class definition in most cases.
- Destructors should be placed after the constructors in the header file.
- Destructors should however be placed LAST in the public class definition. It should be the last function in the cpp file.
- Destructors MUST be made virtual if the class is planned to be derivable or if the class contains one or more virtual methods.
- The first line of a source file (.cpp) should always be the inclusion of the corresponding header file.
- Static member initialization should be made before the implementation of the class’s methods.
- The constructor’s implementation should be placed before any other method implementation.
- The destructor should always be placed at the end of the file. (Facilitates the access to the destructor in the source file.)
- The methods should be implemented in the same order they are declared within the header file. (The exception being the destructor.)
- Methods in a source file should be separated by a comment line like the following :
//////////////////////////////////////////////////////////////////////////
Braces are placed under and in line with keywords :
if( condition ) while( condition ) { { ... ... } }
All if, while, do and for statements must have braces, even if there is only a single statement within the braces. For example:
if( 1 == SomeValue ) { SomeValue = 2; }
This ensures that when someone adds a line of code later there already are braces and they don’t forget to add them. It also provides a more consistent look.
- Indent using 4 spaces for each level.
- Do not use tabs, use spaces. Most editors can substitute spaces for tabs.
- Indent as much as needed, but no more. There are no arbitrary rules as the maximum indenting level. If the indenting level is more than 4 or 5 levels, you may think about factoring out code though.
void func() { if( something bad ) { if(another bad thing ) { while( more input ) { } } } }
- Do not put spaces between key words and parenthesises or functions and parenthesises.
- Put a space between an opening parenthesis and the following element, and just before a closing parenthesis, except when it is an empty parenthesises pair.
void aMethod ( ) // Not good void aMethod() // Good void anotherMethod(int firstParam, int secondParam) // Not good void anotherMethod( int firstParam, int secondParam ) // Good if (aVar == false) // Not good if( aVar == false ) // Good
- When using templates, do not put spaces between keywords and the "<" and ">" symbols.
- Put a space between an opening "<" symbol and the following element, and a space just before the close ">" symbols, except for empty "<" ">" pairs.
template <class T> // Not good template < class T > // Good std::vector<int> // Not good std::vector< int > // Good std::vector<std::pair<int, char>> // Not good std::vector< std::pair< int, char > > // Good
- Falling through a case statement into the next case statement is permitted as long as a comment is included.
- The default case should always be present and trigger an error or assertion if it should not be reached, yet is reached.
- If you need to create variables in a switch case, put all the code of the case in a block.
switch(...) { case 1: ... // FALL THROUGH case 2: { int v; ... } break; default: }
- For clarity, blocks of declarations should be aligned
- The “&” and “*” tokens should be adjacent to the type, not the name.
DWORD m_dword; DWORD* m_pDword; char* m_pChar; int m_int; m_dword = 0; m_pDword = NULL; m_pChar = NULL; m_int = 0;
We should try and make methods have as few parameters as possible. If you find yourself passing the same variables to every method, then that variable should probably be part of the class. Despite this, when a method does have a lot of parameters, format it like this :
int AnyMethod( int arg1, int arg2, int arg3, int arg4 );
This standard has been inspired by a standard developed for another project by Olivier Vaillancourt, based on a standard available at http://home.gna.org/ngl/doc/coding/