[Home]CppCodingStandards/CppStyleAndLayout

TheSourcery | CppCodingStandards | RecentChanges | Preferences | Index | RSS

Style and Layout

Having a common presentation format reduces confusion and speeds comprehension. Therefore the following guidelines are based on the principles of good programming practice and readability.

General Guidelines

All lines should be displayable without wrapping on an 80-character display. If wrapping is required, try to break at an operator, and start the next line with the operator vertically aligned. Each statement should begin on a new line.

Example:

  cout << "This is an example of a line should be wrapped"
       << value << endl;

Comments

It is necessary to document source code. By properly choosing names for variables, functions and classes and by properly structuring the code, there is less need for comments within the code. Comments in #include files are meant for the users of classes, while comments in implementation files are meant for those who maintain the classes. Standardization of comments makes it possible to automatically generate documentation from source code.

Use endline comments in data declarations, for maintenance, and long block ends.

Example:

  int  x;     // counter
  statement;  // :FIX: bug #05273  10/1/98  JAL
  }  // if
  }  // while

Use a single blank line to separate logical groups of code to improve readability. In source files, use two blank lines to separate each function.

Every file should contain a prologue comments to document the files contents, purpose, authorship, and copyright information.

Example:

  //
  //  File:        parser.cpp
  //  Description: This is the TyhcoMUD console command parser.
  //  Rev:         1.2
  //  Created:     Thur. Oct 31, 1991, 12:30:14
  //  Author:      Jon Lambert
  //  mail:        jlsysinc@ix.netcom.com
  //
  //  Copyright 1999, Jon A. Lambert, All rights reserved.
  //
  //  The program(s) may be used and/or copied only with written
  //  permission or in accordance with the terms and conditions
  //  stipulated in the agreement/contract under which the
  //  program(s) have been supplied.
  //
  //  The purpose of this module is to provide services for - blah blah

For comments meant to be extracted by an automated documentation tool, follow the java convention of using the standard C comment delimiters with an extra asterisk on the first one.

Example:

  /**
   * This is a module, class, function, or instance variable comment
   * that will be extracted by an automated documentation tool.
   */

Comments are often said to be either strategic or tactical. A strategic comment describes what a function or section of code is intended to do, and is placed before this code. A tactical comment describes what a single line of code is intended to do, and is placed, if possible, at the end of the code line. Too many tactical comments can make code unreadable, so primarily use strategic comments, unless trying to explain complex code. Comments should reflect the intent or purpose of the code, not a blow by blow description of the code. Descriptive comments should precede every function. Generally we use // for comments or the java convention described above.

  // THE NEXT TWO LINES ARE STRATEGIC COMMENTS
  // This function is supposed to do this:
  //  blah-blah-blah ...
  int MyClass::ComplicatedFunction( int i ) {
    int index = i++ + ++i * i--;  // THIS IS A TACTICAL COMMENT
    return index;
  }

Use #if 0 to comment out code blocks as nested /**/ style comments may or may not be supported by a particular C++ compiler.

Example:

  void example() {
    some code;
    #if 0             // Removed because...
    lots of code;
    #endif
    more code;
  }

Code Block Comments

Code block comments should precede the block, be at the same indentation level, and be separated by a blank line above and below the comment. Brief comments regarding individual statements may appear at the end of the same line and should be vertically aligned with other comments in the vicinity for readability. Code block comments should use the single line comment delimiter //.

Special Comments

Use special comment tags to comment code likely to break during maintenance or to mark areas of code that need work. These comment tags are used to point out issues and potential problems. They are also handy when greping code or for automated extraction by documentation tools.

   * :TODO: topic

Means there's more to do here, don't forget.

   * :BUG: [bugid] topic

Means there's a Known bug here, explain it and optionally give a bug ID.

   * :FIX: information

Documents code that has been fixed as a result of a bug.

   * :WARNING:

Beware of something.

   * :COMPILER:

Documents a possible compiler dependency.

   * :ATTRIBUTE: value

The general form of an attribute embedded in a comment. There may be other occasions where an attribute will be created.

Example:

  // :TODO: JAL 10/05/99: possible performance problem
  // We should really use a hash table here but for now we'll
  // use a linear search.

  // :WARNING: JAL 10/05/99: possible unsafe type cast
  // We need a cast here to get the correct derived type.

Spacing Around Operators

Spacing around operators and delimiters should be consistent. In general, insert one space before or after each operator to improve readability. Use spaces inside of the parentheses around the argument list. Do not use a space within empty argument lists '()' or non-dimensioned arrays '[]'. Do not use spaces around the scope operator '::'. Do not use spaces around the member access operators '.' and '->'. The same applies to unary operators, since a space may give the impression that the unary operand is actually a binary operator.

Example:

  if ( value == 0 ) {             // right
  if (value==0){                  // wrong
  void doIt( int v );             // right
  void doIt(int v);               // wrong
  value = object->GetValue();     // right
  value=object -> GetValue();     // wrong

Indentation and Braces

The contents of all code blocks should be indented to improve readability. Two spaces are recommended as the standard indentation. Ordinary spaces will be used instead of tabs. Since different editors treat tab characters differently, the work in perfecting the layout may be wasted if another editor is later used. Braces should be placed to show the level of indentation of the code block, with the open brace at the end of the statement which starts the block, and the close brace indented to match the statement.

Example:

  int main() {
    doSomething();
  }

  struct MyStruct {
    int x;
    int y;
  }

Pointer and Reference Position

All declarations of pointer or reference variables and function arguments should have the dereference operator '*' and the address-of operator '&' placed adjacent to the type, not the variable. The characters '*' and '&' should be written together with the types of variables instead of with the names of variables in order to emphasize that they are part of the type definition. Pointer variables will be prefixed with 'p' or 'p_'. Reference variables are prefixed with 'r' or 'r_'.

Example:

  char*   p_text;                 // right
  char    *text;                  // wrong
  char*   doSomething( int* x );  // right
  char    *doSomething( int *x ); // wrong

Control Statements

All control statements should be followed by an indented code block enclosed with braces, even if it only contains one statement. This makes the code consistent and allows the block to be easily expanded in the future.

Example:

  if ( value == 0 ) {        // right
    doSomething();
  } else if ( value == 2 ) { // note position of cascaded if statement
    doSomething2();
  } else {
    // nothing               // comment is used as space-holder
  }

  if ( value == 0 ) doSomething(); // wrong - no block, not indented

  if (value == 0)
    doSomething();                 // wrong - no block

At times, everything that is to be done in a loop may be easily written on one line in the loop statement itself. In such cases, nevertheless place an empty block after the statement to make completely clear what the code is doing.

  // Flow control structure without statements
  // Wrong
  while ( /* Something */ );

  // Right
  while ( /* Something */ )
  {
    // do nothing
  }

More examples of statement formatting:

  while ( value < 300 ) {
    do_something();
  }

  do {
    do_something();
  } while ( value < 300 )  // note: ending brace and while on same line

  switch ( value ) {
    case 1:
      do_something();
      break;
    case 2:
    case 3:
      do_something2();
      break;
    default:
      break;               // final break required
  }

Conditional Statements

Conditional statements found in if, while, and do statements should be explicit based on the data type of the variable being tested.

Example:

  int value = GetValue();
  if ( value == 0 ) {               // right
    DoSomething();
  }
  if ( !value ) {                   // wrong - not explicit test
    DoSomethingElse();
  }
  bool value = GetValue();          // could be RWBoolean too.
  if ( !value ) {                   // right
    DoSomethingElse();
  }

Variable Declaration

Each variable should be individually declared on a separate line. Variables should be grouped by function and next by type, with groups separated by a blank line. Variable names should be aligned vertically for readability.

  // mail reader variables
  int*    g_socket;       // mail reader socket
  int     b;              //
  double  d;              //
  double  e;              //

  double  a;              //
  int     b;              //

External Variable Declaration

All external variables should be placed in header files. In general the use of global variables is discouraged. Use the following method to allow external variables to be created only once while using a single declaration. In the header file which declares the global variable, use a flag to cause the default action on inclusion to be referencing of an externally created variable. Only in the source file that wants to actually create the variable will this flag be defined.

Example:

In the header file filename.h:

  #ifdef FILENAME_INIT
  #define EXTERN          // create the variable (only in filename.cpp)
  #else
  #define EXTERN extern   // just a reference (default)
  #endif
  EXTERN ErrorLogger errorLog;
  #undef EXTERN

All of the source files should include this header file normally:

  #include "filename.h"

While the following should appear only in the source file where you actually want to declare the variable and allocate memory for it:

  #define FILENAME_INIT
  #include "filename.h"
  #undef FILENAME_INIT

Numeric Constant Declaration

Use only the uppercase suffixes (i.e. L, X, U, E, F) when defining numeric constants.

Example:

  const int    value  = A73B2X;  // right, hexadecimal constant
  const double evalue = 1.2E9;   // right, scientific notation constant

  const float  fvalue = 1.2e9;   // wrong, lowercase e

Enumerated Type Declaration

The enum type name and enumerated constants should each reside on a separate line. Constants and comments should be aligned vertically.

Example:

  enum CompassPoints {    // Enums used to specify direction.
          DIR_NORTH_E = 0,      //
          DIR_SOUTH_E = 1,      //
          DIR_EAST_E  = 2,      //
          DIR_WEST_E  = 3       //
  };

Struct and Union Declaration

The struct type name and structure members should each reside on a separate line. This format separates the members for easy reading, is easy to comment, and eliminates line wrapping for large numbers of members. Each struct should have a one-line description on the same line as the type name. Each member should have a comment describing what it is, and units if applicable. Members and comments should be aligned vertically.

Example:

  struct MeaningfulName {   // This is a struct of some data.
    int     FirstInteger;   // This is the first int.
    int     SecondInteger;  // This is the second int.
    double  FirstDouble;    // This is the first double.
    double  SecondDouble;   // This is the second double.
  };

Class Declaration

All class definitions should include a constructor, (virtual) destructor, copy constructor and assignment operator. If the class has a pointer, provide a deep copy constructor. If any of these four are not currently needed, create stub versions and place in the private section so they will not be automatically generated, then accidentally used. All classes should have public, protected, and private access sections declared, in this order. Friend declarations should appear before the public section. All member variables should be either protected or private. No member functions are to be defined within the class definition, although trivial inline functions (e.g., {} or { return x; }) may be defined within the declaration itself. It is recommended that definitions of inline functions follow the class declaration. Attributes should each have a one line description. Members and comments should be aligned vertically.

Example:

  class Value : public BaseValue {
  public:
    Value();                           // Default constructor.
    Value( const Value& r_old_value ); // Copy constructor.
    virtual ~Value();                  // Destructor.
    // Assignment operator
    const Value& operator=(const Value& r_source);
    void SetValue( int new_value );    // Set mValue.
    int GetValue();                    // Get mValue.

  protected:
    void IncrementValue();             // Increment value.

  private:
    int mValue;                        // The value.
  };

  inline int Value::GetValue() const { // Outside of class declaration
    return mValue;                     // Note this is trivial
  }

Functions

Always provide the return type of a function explicitly. When declaring functions, the leading parenthesis and the first argument, if any, are to be written on the same line as the function name. If space permits, other arguments and the closing parenthesis may also be written on the same line as the function name. Otherwise, each additional argument is to be written on a separate line (with the closing parenthesis directly after the last argument).

Example:

  // The left parenthesis always directly after the function name
  void foo ();    // no
  void foo();     // yes

Right and wrong ways of declaring formal arguments for a function:

  // Right:
  int my_complicated_function( unsigned unsigned_value,
        int int_value,
        char* p_char_pointer_value,
        int* intPointerValue,
        myClass* p_my_class_pointer_value,
        unsigned* p_unsigned_pointer_value );
  // Wrong:
  int my_complicated_function( unsigned unsigned_value, int int_value,
  char* p_char_pointer_value, int* p_int_pointer_value, myClass*
  p_my_class_pointer_value, unsigned* p_unsigned_pointer_value );


TheSourcery | CppCodingStandards | RecentChanges | Preferences | Index | RSS
Edit text of this page | View other revisions
Last edited September 15, 2005 8:54 pm by JonLambert (diff)
Search:
All material on this Wiki is the property of the contributing authors.
©2004-2006 by the contributing authors.
Ideas, requests, problems regarding this site? Send feedback.