C++ Coding Standard

Author / Автор: Sergey Satskiy
Publication date / Опубликовано: 08.07.2005
Version / Версия текста: 1.3

Introduction

The coding standard prescribes rules of writing C++ code. All the rules which can be applied to a C code must be used in the programs written in C.

The standard considers features of some auxiliary developer tools. Doxygen is an example of such a tool.

The document is rather a quick reference than a complete description of the selected rules. The purpose of the document is to give a feeling of the coding style.

Deviations are acceptable only in case if they improve code readability.

The standard is not a panacea against writing a bad code.

The standard does not describe semantic aspects of the C++ usage in general. The further editions could be extended with that.

Files

  • Header files must use the .h extention. C++ source files must use the .cpp extention and C source files must use the .c extention.
  • In most of the cases a single header file must content a declaration of a single class. Defenitions of multiple auxiliary classes are acceptable for example predicate classes. Those auxiliary classes are usually much simpler and shorter than the main for the file class.
  • A .cpp source file name must match the name of a corresponding .h file. The .cpp file must content definitions of all the classes which were declared in the corresponding .h file.
  • The max length of a single line in a file is limited to 80 characters. In case of divisions use a vertical alignment with a shift.
  • Max number of lines in a single file is limited to 1000.
  • Make efforts to limit a single function size to 100 lines.
  • The rules of forming file names are the same as rules of forming identifiers (see further).
  • The special characters TAB and page break must not be used. The TAB character must be substituted with the appropriate number of spaces (an editor auto substitution feature may be used). An exception for the TAB character is Makefiles where the TAB character has a special meaning.
  • Each file must have a block of remarks at the very beginning which is followed by the rest of the file content.
  • The entire content of a header file (except the leading remarks block) must be surrounded by conditional compilation directives. For example the file MyClass.h will have the following conditional compilation directives:

#ifndef MYCLASS_H
#define MYCLASS_H

. . .

#endif

  • All the #include directives must be at the beginning of a file.
  • All the included files must be sorted and grouped. The sort order is from low to high level files. One or more empty lines are used to group including files, for example:

#include <fstream>
#include <iomanip>

#include <XML/DOM.h>
#include <XML/Node.h>

#include "UI/PropertiesDialog.h"
#include "UI/MainWindow.h"

Identifiers

  • The correct English language (the right spelling) must be used for forming identifiers.
  • Usage of non common abbreviations and shortenings must be minimized. Usage of common used abbreviations in a particular domain area is acceptable, for example: NMEA.
  • Each word in an identifier must start with capital. Words are written with no separators. Example:

MyOwnIdentifier

  • Prefixes are allowed for user data types (classes, structures, enumerations). Each developer may use their own prefix. Example:

SMyOwnClass

  • The '_' character must not be used in identifiers
  • The reserved by international standards identifiers must not be used. The table below describes those reservations.
Reserved Identifiers Standard
Double _ in any place ISO C++, ANSI C
Single _ at the beginning ISO C++, ANSI C
E[0-9A-Z]. . . ANSI C
is[a-z]. . . ANSI C
to[a-z]. . . ANSI C
LC_. . . ANSI C
SIG[_A-Z]. . . ANSI C
str[a-z]. . . ANSI C
mem[a-z]. . . ANSI C
wcs[a-z]. . . ANSI C
. . ._t POSIX

  • Use the scheme

[ Prefix + ] [ Noun | Adjective +] Noun

for type names. Example:

class SDataHeap

  • Use the scheme

Verb [ + Noun ]

for method and function names. Example:

void  SetNewName ( const std::string &  NewName );

  • bool variables usually use the Is or Has prefix. Example:

bool    IsDoorClosed;

  • File names usually match the class names which are defined in those files.
  • Try to select class and its method names so that a call like

MyObject.Method()

could be read as a phrase with a sense.

  • Local object names which hide external names must be avoided
  • If a name of the formal class method argument is conflicting with the class data member it is allowed to use formal class method argument identifier which starts with low register character. Example:

class SAlarm
{
    public:
        SAlarm( SSeverity  severity ) : Severity( severity ) { }

    private:
        SSeverity     Severity;
};

  • Avoid names which differ slightly from each other especially using similar characters like '0', '1' and 'O', 'l'.
  • Cycle counter identifiers may be single character ones. Prefer to use the following characters in the given priority order: k, j, m, n, i.
  • If macroses are still used their identifiers must use capitals only. Use the '_' character to separate words in the macroses identifiers.

Source Code Layout

  • Write code by "chunks" separated by emply lines.
  • Shift of 4 spaces must be used to format source code.
  • The vertical alignment must be used.
  • Variables declaration blocks must be aligned. Example:

int             SomeIntegerValue;    //!< Remark1
unsigned long   SomeLongValue;       //!< Remark2
bool            SomeBooleanValue;    //!< Remark3

The data type name start position as well as variable name and remark start positions must match a tab position. There must be at least two spaces after a data type name. The '*' and '&' characters are attached to a data type but not to a variable name. There must be at least two spaces before the starart position of a remark.

int *               SomeIntegerValue;   //!< Remark1
unsigned long &     SomeLongValue;      //!< Remark2
bool *              SomeBooleanValue;   //!< Remark3

  • Curly brackets must be aligned in accordance with the Allman style:

void  DoSomething ( void )
{
    if ( x != y )
    {
        y = x;
    }
    else
    {
        ;    // Do nothing
    }            
}

Each curly bracket occupies a separate line. Exception: definition of empty inlined methods in header files.

  • Statements while, for and if must always use blocks in curly brackets even if there is no synax necessity.
  • The switch statement cases must be aligned in accordance with tab positions. The default alternative must be in place for each switch statement. Each case alternative must have the break statement. Example:

switch ( Variable )
{
        // ...
    case 1:
        break;

        // ...
    case 2:
        break;

        // ...
    default:
        NeverGetHere;    //  See Assertion.hpp
        break;
}

  • Long lines division must be after , ; and other statements.
  • Comparison characters must be surrounded by spaces

if ( a <= b )

  • A space must follow every keyword

for ( ; ; )

  • A space must follow ',' and ';'. There must not be spaces before them.
  • There must not be spaces before '(', '[' and '<'. A space must follow them.
  • Spaces must surround ':', ')', ']', '>' and '='. Exception is a call of function without arguments. Round brackets without spaces are allowed in this case. Example:
MyVector.end();
  • There must not be spaces around '.' and '->'.
  • There must not be space after dereferencing (*) and taking address (&) operations.
  • There must not be space after unary operations.
  • There must not be space between the increment and decrement statements and an object they are applied to.
  • Math operations symbols must be surrounded by spaces.
  • The template keyword with a list of parameters must occupy a separate line. Example:

template < typename  EventType, typename  StateType >
class SStateMachine
{
    . . .
};

  • Function and method prototypes must use names for the formal arguments. At least two spaces must be between an argument type and argument name. In case of carrying to the next line a vertical alignment must be used.

Remarks

Remarks are given in form to be suitable for a generation of documentation by a source code by doxygen. In order to mark remarks the following character are used: //!, /*! . . . */ and //!<. The last means that the remark is related to the previous element. In addition to that @param tag is used to describe function parameters and @return tag is used to describe return values.

  • Correct English is used for remarks
  • A remark size is proportional to the complexity of an object it is related to.
  • Prefer the C++ remark style: //
  • Multy line remarks must be aligned

// First line
// Second line
// Third line

or

/* Short line                     */
/* Extended size line             */
/* Very very very very long line  */

  • In case of multy line C-style remark prefer the following layout:

/*
 *  Some remarks
 *  More remarks
 */

  • Remarks which precede an element must be layouted with 4 space shift. Example:

    //! This is the remark
bool    SomeBooleanValue;

    //! This is the first line
    //! More detailed description
bool    SomeBooleanValue;

  • There are two ways of remarking: preceeding remark and remark which is layouted at the same line as the element it is describing. In the last case at least two spaces must be between a variable name and the beginning of the remark.

    //! This is the first type of the remark
bool    SomeBooleanVariable;

bool    SomeOtherBooleanVariable;    //!< Many lines remark
                                     //!< Second line of the remark

  • Each variable must be remarked
  • Each user data type (class, structure, union etc.) must be preceeded with the similar remark:

    //! The SMyOwnClass is created for the special purpose
    //! And should be used everywhere it is possible
    //! With no obligation to send a post card
class SMyOwnClass
{
    . . .
};

  • Each function (class method) must be preceeded with the similar remark:

    //! The function transforms string representation into integer
    //! @param InputValue is a stringed value
    //! @param Base is a scale of notation
    //! @return transformed value of the given scale of notation
long SuperFunction ( const string &  InputValue, long  Base );

  • Each namespace must be preceeded with a remark
  • At the very beginning each file must have the similar remark:

//
// File:          Template.h
//
// Creation date: July 27th 2003
//
// Author:        Sergey Satskiy
//
// Purpose:       Template for all the headers
//
// Copyright (c) 2005 Sergey Satskiy
//
// $
//

Each line starts from the column 0.

  • If doxygen does not recognize properly many lines remark in C++ style, use the following notation:

    /*! The function transforms string representation into integer
     *  @param InputValue is a stringed value
     *  @param Base is a scale of notation
     *  @return transformed value of the given scale of notation
     */
long SuperFunction ( const string &  InputValue, long  Base );

  • Other doxygen tags are allowed in the remarks.
  • Additional to mandatory remarks are welcomed.

Language Usage

  • Use 0 instead of NULL.
  • The const modifier must be used in any place where it is possible.
  • Use const instead of #define for constant definitions.
  • A class declaration must use the following sequence of sections: public, protected, private. A class definition must use the same order.
  • Do not use the goto statement.
  • Avoid deep nesting of statements, blocks and structures. Prefer a way with a simple check and going out.
  • A single stament must declare a single variable.
  • Avoid usage of the '?' statement.
  • Avoid macroses usage.
  • Nested if else statements must be aligned as they were independent statements.
  • Initialize variables at the declaration everywhere it is possible.
  • Constructors must initialize all data members unless it is impossible. Initialization must be done in a list of initialization unless it is impossible. Remember the sequence of initialization.
  • Do not forget to make base classes destructors virtual.
  • Use STL containers and algorithms.
  • Prefer explicit constructor call in the variable initializations.

int     Salary( 0 );    // Not int    Salary = 0;

for ( vector<int>::iterator  k( MyVector.begin() ); k != MyVector.end(); ++k )

  • The assignment statement must be one in a single line. Multiple assignments are not allowed.
  • Do not use comparisons in math expressions

NumberOfDays = ( IsLeapYear() == true ) + 28;    // Not allowed

  • Non boolean expression results must use a comparison statement. Do not use implicit != 0.

if ( ObjectPointer != 0 )    // OK
if ( ObjectPointer )         // Not allowed

  • Do not use assignments in comparison statements
  • Do not use the ',' statement.
  • Use C++-style cast statements instead of implicit casts or C-style casts.
  • Use for ( ; ; ) to write an infinite loop.
  • Use exceptions to implement error handling.
  • Use sizeof(. . .) instead of constants.
  • Remember about class methods which are generated by a compiler by default.
  • Set the complition warnings level to max available. Make the compilation smooth without a single warning.
  • Avoid overloading by numerical and pointer types. It leads to ambiguities.
  • Use embedded bool type.
  • Do not use RTTI if possible.
  • Prefer reference to pointer.
  • Prefer long type to int.
  • Prefer double type to float.
  • Use the prefix form of ++ and - everywhere it is possible.

Namespaces

  • Namespaces should be used widely.
  • Library code must be placed into a namespace.
  • Library code must not use the using namespace directive for the necessary definitions. It must use the explicit scope resolution statement instead.

Reference

  1. Scott Meyers. Effective C++
  2. Scott Meyers. More Effective C++
  3. Herb Sutter. Exceptional C++
  4. CoreLinux++ coding standard
  5. Arctic Labs C++ Coding Standard
  6. Baldwin's C++ coding standard
  7. Brett Slocum C++ coding standard
  8. Geotechnical Software Services C++ Coding Standard
  9. European Laboratory for Practice Physics C++ Coding Standard
  10. SoftQuad's C++ Coding Standard
  11. Logikos's C++ Coding Standard
  12. Notes On Writing Portable Programs In C
  13. Ahntech C++ Coding Standard
  14. Object Oriented Coding Standard
  15. Programming in C++, Rules and Recommendations
  16. Quantum Coding Standard
  17. Recommended C Style and Coding Standard
  18. Automating Corporate Source Code Compliance
  19. Yongling Ding C++ Coding Standard
  20. Wildfire C++ Coding Standard


Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.

Разрешается копирование и распространение этой статьи любым способом без внесения изменений, при условии, что это разрешение сохраняется.
Last Updated: January 28, 2007