I have forgotten
my Password

Or login with:

  • Facebookhttp://facebook.com/
  • Googlehttps://www.google.com/accounts/o8/id
  • Yahoohttps://me.yahoo.com

Programming Guidelines

The following are suggestions on how to write better code. This is an evolving standard that we believe applied generally to most programming languages, and as styles change we would welcome your suggestions for improvement.

General

Write Clearly

Don't be overly clever. Just because you can do something in a single line of code doesn't mean you should. Do not write code just for the compiler; write the code for you and your fellow programmers. Remember it may be you who returns to this code days, months, or years later and can't remember what that complex statement does. Never sacrifice clear code for "efficient" code.

Remember: Clearly written code is 'self' commenting, there should be no need for blocks of comments to describe what is going on. If that isn't the case, consider using more descriptive variable names, and breaking the code up into more distinct modules.

top

Make it Work, then Make it Fast

Often during development, developers want to get the most "bang" for their money. If you write code that works, and the interface is clear and correct, you can always go back later and make it faster. Strive to make it correct and readable first and fast second. Fast wrong code is still wrong code.

top

Structure

The process of understanding a particular program is speeded up if all programs are organised in the same way. In C++ all files should be organised with the declaration/body of a function above the code where the function is being used. Thus the main function(s) within a program (*.cpp) should always appear at the bottom of the code, i.e.

  1. #include statements
  2. functions' bodies
  3. class bodies
  4. main function body

A header file (*.h) should contain all the function and class definitions that are intended to be visible to users who include the header. Except in the use of template<>’s, headers should generally only contain the definitions of functions and classes, not the body of these functions or classes. Thus the standard order should be

  1. #include statements
  2. #define statements
  3. struct definitions
  4. function definitions
  5. class definitions
top

Class Declarations

The following is a list of the parts of a class declaration in the order that they should appear:

  • Class statement
  • Constants and static variables
  • Member variables
  • Constructors
  • Functions
//! A class to do something
class SomeClass : public SomeBaseClass
{
public:
  int m_numPeople;      //! Number of People
protected:
  int m_numCanines;     //! Number of Canines
private:
  int m_numFelines;     //! Number of Felines
  
  //!Default constructor
  SomeClass();
  //!A Function
  FunctionA();
};
top

Member Variables and Functions

First list the public, then protected, and then the private. By placing the public section first everything that is of interest to a user is gathered at the beginning of the class definition. The protected section may be of interest to designers when considering inheriting from the class. The private section contains details that should have the least general interest.

For readability, all member variables of a class should be indented to the same column.

top

Public Member Class Variables

A public variable represents a violation of one of the basic principles of object-oriented programming, namely, encapsulation of data. For example, if there is a class of the type BankAccount, in which accountBalance is a public variable; any user of the class may change the value of this variable. However, if the variable has been declared protected, it's value may be changed only by the member functions of the class (e.g. setAccount() and getAccount()). This prevents some other arbitrary function changing data; which may lead to errors that are difficult to locate.

If public data is avoided, it's internal representation may be changed without users of the class having to modify their code. This is a core principle of class design, where the existence of a public interface for the class allows the internal implementation of a class to be changed without affecting the users.

Conversely, for classes or structs that act as containers for a collection of data variables, without providing significant additional functionality (beyond perhaps initialisation, copying and destruction), it is simply ludicrous to provide a setX() and getX() for each member variable. Therefore, when designing a class great care should be taken to ascertain its purpose and intended use.

top

Function Arguments

Functions having long lists of arguments that look complicated and are difficult to read. In general, if a function has more than five parameters then perhaps it should be redesigned. One alternative is to package the parameters into a class or structure that is then passed to the function.

Try to keep functions short. One compelling reason is that if an error situation is discovered at the end of an extremely long function, it may be difficult for the function to clean up after itself before reporting the error to the calling function. By always using short functions such an error can be more exactly localized.

top

Constant Correctness

In the declaration of input variables for a function, a const keyword should precede the type definition of all variables that are not changed during the execution of the function.

It is usual to pass basic type variable (such as int, double etc) by value. In this instance, the use of the const keyword is merely to aid readability – variables defined as const will never change in the function.

For large variables/objects it is common to pass these by either reference or by pointer. Through the use of a const keyword, variables/objects that are not changed by the function can be specifically declared within the function definition. The compiler will always ensure adherence to this rule, so anyone using a function can instally see the potential for a variable to be changed. This also simplifies debugging.

Note, although a standard ‘object reference’ can be converted into a ‘const object reference’, this conversion cannot be performed the other way around. However, as you might expect, a function that takes an object by value (it makes its own local copy), will accept both const reference and nonconst variables.
double setZ(const Coordinate &point); 
double setY(Coordinate &point);
double setX(Coordinate point);

double init(const int x, const Coordinate &A, Coordinate &B)
{
  int a=x;      //ok
  x++;          //illegal

  point.m_x=x;  //illegal,  where m_x is a member variable of Coordinate

  SetX(A);  //ok
  SetY(A);  //illegal 
  SetZ(A);  //ok

  SetX(B);  //ok
  SetY(B);  //ok
  SetZ(B);  //ok
}

Within a class, the const keyword can also be used to designate member functions that do not alter other members of that class. This has the same distinct benefits for debugging as those discussed above, and also assist readability. Note that for obvious reasons, a const member function cannot call a nonconst member function.

class A
{
  int m_size;

  int getSize()            // bad - doesn't alter any member functions, so should be const
  { return m_size; }

  
  int getTheSize() const   // good
  { return m_size; }

  int doSomething() const  
  {
    return m_size++;       // illegal
  }
  
  int add() const
  {
    return getSize()+1;    // illegal, getSize() isn't const, so theoretically my alter class
  }
};
top

Code Formatting

Indentation

Always a touchy subject. The issue of indentation is important for the purposes of common code formatting. The standard we would like to adopt is to use 2 spaces for indentation. To ensure compatibility across development tools, indentation should use spaces instead of tabs.

top

Line Length

Avoid lines longer than 80 characters. This is intended to make the code more readable in an editor, as well as to allow for easier printing of the source code.

top

Blank Lines

Blank lines improve readability by setting off sections of code that are logically related.

Two blank lines should always be used between the blocks listed under “Order of code sections” and between:

One blank line should always be used in the following circumstances:

  • Between functions.
  • Before a block comment or leading comment.
  • Between logical sections inside a function to improve readability.
top

Spacing

In our opinion, code is more readable if spaces are not used around the ‘.’ operator. The same applies to unary operators such as increment ("++") and decrement ("--") since a space may give the impression that the unary operand is actually a binary operator.

  • Do not use spaces around '.' or between unary operators and operands.
  • Spaces around binary operators and operands may increase readability. Too much can have opposite effect. The user of spaces should also draw attention to the operator precedence.
  • When calling a function, the left parenthesis should immediately follow the name without any spaces.
  • A space between a keyword and a parenthesis should not be used
  • Spaces around parentheses may be used in expressions to increase readability
// good examples
a += c + d;
a = (y + x*(a+b)) / (c*d);              // spaces are removed to improve readability
a++;
aDate.SetYear(1994);

for( int i=0; i<10; i++ )
{
}

// bad examples
a+=c+d;
a=(y+x*(a+b))/(c*d);
a = ( y + x * ( a + b ) ) / ( c * d )
a = ( y+x * (a+b)) / (c+d)              // operator precedence evaluates x*(a+b) first, prior to adding y
a ++;
aDate . SetYear(1994);
top

Breaking Lines

The breaking of a line of code aids readability. If a line needs to be broken up into 2 or more lines, break it according to these general principles:

  • Break after a comma or an operator.
  • Prefer higher-level breaks to lower-level breaks.
  • Align the new line with the beginning of the expression at the same level on the previous line.
  • If the above rules lead to confusing code, or to code that is squashed up against the right margin, use two indentations instead.
// good -- correct alignment
var = someFunction1(longExpression1,
      someFunction2(longExpression2, lonExpression3));

// good -- break at higher level
longName1 = longName2 * (longName3 + longName4 - longName5) +
            4 * longname6;

// avoid -- this is a break at a lower level
longName1 = longName2 * (longName3 + longName4 - longName5) 
          + 4 * longname6;
					
// good
if((condition1 && condition2) || (condition3 && condition4) ||
   !(condition5 && condition6)) 
{
  doSomethingAboutIt();
}
top

Statements

Only one statement should be written on each line. Placing multiple statements on the same line can cause problems. Many debuggers cannot handle multiple statements on a single line.

argv++;       		// good
argc--;       		// good
argv++; argc--;	    // avoid
top

Variables

Avoid assigning several variables to the same value in a single statement. It makes it hard to read. Also, do not use embedded assignments in an attempt to improve run-time performance - this is the job of the compiler.

// avoid the following
fooBar.fChar = barFoo.lchar = 'c';
d = (a = b + c) + r;

// do it this way instead
fooBar.fChar = 'c';
barFoo.lchar = 'c';

a = b + c;
d = a + r;
// good variable declarations
int level = 4;			// indentation level
int size = 256; 	  	// size of table

// avoid
int level=4, size=256

top

Blocks and Braces

Blocks, also called compound statements, are constructs that contain lists of statements enclosed in braces ‘{}’. The placement of braces is the subject of great debate concerning the appearance of code. We recommend the style that, in our opinion, more clearly shows enclosure and block ownership. Other styles may well provide more compact code.

  • Braces ‘{}’ which enclose a block are to be placed in the same column, on separate lines directly before and after the block. The enclosed statements should be indented one more level than the compound statement.
  • Trailing comments should be used on the closing brace when the block structure is complex, or there are several levels of nesting.
if( x == 0 )
{
  . . .
}

try
{
  . . .
}
catch( Exception )
{
  . . .
}

top

Write Module Code

Code should be broken down into smaller pieces in order to make testing easier and to facilitate re-use of code. Functions that span several pages of printed text are hard to follow, harder to debug and are less likely to be reusable in alternative applications. As a general rule, a function should not span more than 2 pages (or 100 lines). Furthermore, two or more functions can be adapted by others for a wider range of uses than one single function.


top

Break Complex Equations into Smaller Pieces

Complex equations containing many operators should be broken down into smaller pieces, with suitably name local variables to describe the individual portions of the code. This not only makes the code more understandable (self documented), but it is also easier to analyse the values of specific parts of the equation during debugging.

If only locally defined variables are used then writing code in this way is NOT less efficient - the code will run just as fast. However, it is important to constrain the scope of these local variables, which is achieved when you code in a modular fashion. To further aid the compiler you can encapsulate the locally used variables with { }.

// poor
double num=(A * 2 * cos(w * t)) * sin(k * x) * cosh(k * d) + 2 * B * sin(k * x - w * t);

// better
...
double num;
{
  double Amp_A  = A * 2 * cos(w * t);
  double Wave_A = Amp_A * sin(k * x) * cosh(k * d); 
  doule Amp_B  = B * 2;
  Wave_B = Amp_B * sin(k * x - w * t);
  num    = Wave_A + Wave_B
}
...

top

Parenthesis

It is generally a good idea to use parentheses liberally in expressions involving mixed operators to avoid operator precedence problems. Even if the operator precedence seems clear to you, it might not be to others - you should not assume that other programmers know precedence as well as you do.

if(a == b && c == d)      // avoid
if((a == b) && (c == d))  // good

x >= 0 ? x : -x;			  // avoid
(x >= 0) ? x : -x;			  // good

top

Flow Control Statements

There are many styles for formatting control statements, so consistency becomes very important. Multiple styles within one file or set of files is at best distracting and at worst error-prone.

  • Statements must never be included on the same line as the control expression. By putting statements on the same line as the control expression it can cause confusion when tracing control flow with most debuggers.
  • The flow control primitives if, else, while, for and do should usually be followed by a block, especially when the executed statement is fairly complicated. This also makes it easier to add statements without accidentally introducing bugs due to forgotten braces.
// if-else
if( expression )
{
  statements
}
else if( expression )
{
  statements
}
else
{
  statements
}

// for loop
for( expression1; expression2; expression3 )
{
  statements
}

// while
while( expression )
{
  statements
}

// do-while
do
{
  statements
} while( expression );

top

Switch Statements

  • If a break is not used at the end of a case and the code “falls through”, a comment should mention that the code intentionally falls through to the next case.
  • A break should be used at the end of the last case, even though it may not be explicitly necessary. This prevents an unintentional fall-through error if another case is added later.
  • The ‘default’ case should normally appear as the last case, unless it falls through to another case.
  • Try to indent all the statements so they start at the same column.

 

switch( expression )
{
  case const1: statements
		break;
  case const2: statements
		break;
  case const3: statements    
	// falls through
  default:
		           statements
		break;
}

top

Breaking Within Loops

Breaks within loops should be treated as normal statements.  However, it is recommended that the break be commented.

for( propID = 0; propID < MAX_PROP_ID; propID++ )
{
  while( m_eventLoss[propID] < MAX_PROP_ID )
  {
    if(..) break;  // from while eventLoss[propID]
  }
}
top

Goto Statements - Don't Use!

Use Goto sparingly, since they break the structured flow of the program and can make code difficult to follow. Two harmless places to use goto's are when breaking out of multilevel loops, or to jump to a common 'error catching' location. For example:

for(...)
{
  while(...)
  {
    ...
    if(disaster) 
      goto error;
  }
}
...


//*** ERROR CATCHING ****************************
//*** Fixing the mess after disaster happened ***
error: 
  ...
// *********************
top

Exception Handling

How to handle exceptions depends a lot on the application (console, windows application, etc) and a complete treatment is beyond the scope for this document. However, the basic guide line for all exception handling is:

A function that finds a problem it cannot cope with should throw or re-throw an exception, hoping that it's (direct or indirect) caller can handle the problem. A function that wants to handle that kind of problem should indicate that it is willing to catch that exception.

top

Error Catching - assert and verify

An assertion statement specifies a condition that you expect to hold true at some particular point in your program. If that condition does not hold true, the assertion fails, execution of your program is interrupted, and the Assertion Failed dialog box appears.

The key feature of the assert statement is that it is only included in 'Debug' executable code, with these statements being automatically removed for Release code. As such, assert only slows down Debug executables, but has no ill effect (either speed or size) on the Release code.

Through the liberal use of assertions in your code, you can catch many errors during development. A good rule is to write an assertion for every assumption you make. If you assume that an argument is not NULL for example, use an assertion statement to check for that assumption. In addition, the readability of code can be greatly improved through their use, as the reader can easily see what these assumptions are.

#include <assert.h>

void add(double** data, int N)
{
  assert(data!=NULL);
  assert(N<MAXSIZE);
  ...
}

Because assert expressions are not evaluated in the 'Release' version of your program, you need to make sure that assertions does not have side effects.

#include <assert.h>
// Never do this
assert(nM++>0);    
// At this point, nM will have different values 
// in the debug and release versions of the code.

// Better
assert(nM>0);
NM++;

// UnSafe
assert(myFunc()>0);      // myFunc() might have side effects.

In MFC, there is a VERIFY macro that can be used instead of ASSERT. VERIFY evaluates the expression but does not check the result in the Release version, therefore there is now an overhead related to the evaluation of the expression. We feel VERIFY adds confusion to the code, so we strongly discourage its use. Expressions intended to be in the release code should always be evaluated as a part of regular code.

Naming Conventions

The appropriate naming of identifiers is important for a variety of reasons. If clear and meaningful identifiers are used, then it aids in the understandability of the code, and also reduces the need to provide overly detailed comments. Consistency of naming also aids in the ability of developers to read and understand the code. By applying consistent conventions to naming, users of the classes will become familiar with the style and begin to "expect" all classes to follow the same style.

Apply these general rules when naming identifiers:

  • Choose names that suggest the usage.
  • Do not use names that differ only by the use of uppercase and lowercase letters.
  • Do not use names that include abbreviations that are not generally accepted.
  • Do not use underscores to separate words or begin an identifier; they are allowed as separators for static finals, and a specific exception for class member variables.
  • Do not use dollar sign ‘$’ characters in identifiers.
  • It is recommended that identifiers not be extremely long (over 32 characters).

Identifier

 

Naming Convention

 

Example

Classes

 

Class names should be nouns, in mixed case with the first letter of each internal word capitalized. Try to keep your class names simple and descriptive. Use whole words and avoid acronyms and abbreviations (unless the abbreviation is much more widely used than the long form, such as URL or HTML).

 

class Raster;
class ImageSprite;

Functions

 

Functions should be verbs, in mixed case with the first letter lowercase, with the first letter of each internal word capitalized.

Functions to get and set an attribute that might be thought of as a variable ‘V’ should be named ‘getV’ and ‘setV’.

A function that tests a boolean condition ‘V’ about an object should be named isV.

 

run();
runFast();
getBackground();

Variables

 

Names that consist of more than one word should have internal words capitalized.

One-character variable names should be avoided except for temporary, counter variables such as those found in looping constructs. In such cases the variable type prefix may be omitted.

A common standard for naming variables, known as Hungarian notation, is a popular standard. However, strict adherence to this methodology can not only be annoying, but it can also degrade code reasability.  Therefore, as a general rule, variables that have a large scope (they are used in many places, a long way from where they are defined – global variables are a classic example) should begin with lowercase letters that indicates their type.

The Primitives letters describing these type being:

boolean b
short s
int i
long l
float f
double d
char c
 

int i;

int iNoContracts;

char cDistType;

char** ppcArrayOfStrings;

double* pdWidth;

Pointer Variables

 

All pointer variables must be prefixed with a ‘p’.

If the pointer is a pointer to another pointer another ‘p’ may be added.

 

double* pdNumber;

char** ppcArrayOfStrings;

Member Variables

 

Member variables should begin with m_ to differentiate them from local variables; no other underscores should be used.

The name following the underscore should begin with a lowercase letter, with multiple words identified by mixed casing.

 

private int m_iPropNum;

private double m_dBalance;

Constants

 

The names of static final variables should be in all capital letters without leading underscores. Underscores should, however, separate words in a constant.

 

#define MIN_WIDTH 100

#define MAX_WIDTH 200

top

Overloading Functions

Overloading functions can be a powerful tool for creating a family of related functions that only differ in the type of data provided as arguments. If not used properly (such as using functions with the same name for different purposes) they can, however, cause considerable confusion. When overloading functions all variations should have the same semantics (be used for the same purpose).

top

Effective Commenting

Comment on your code in a manner which is compact and easy to find, but do not over-comment. Commenting every line of code may seem helpful, but it is not. Make your comments count; they should clarify the code, not complicate it. Remember that by properly choosing names for variables, functions, and classes and by properly structuring the code, there is less need for comments within the code. It is always more effective to choose meaningful variable names than to use a vague name with a good comment. Source code should be virtually self-documenting.

  • In general, comments should be used to give overviews of code and provide additional information that is not present in, or clear from, the code itself.
  • Comments should contain only information that is relevant to reading and understanding the program. For example, information about how the corresponding package is built or in what directory it resides should not be included as a comment.
  • Commenting of nontrivial or non-obvious design decisions is appropriate.
  • Avoid creating comments that are likely to get out of date as the code evolves.
  • The frequency of comments sometimes reflects poor quality of code. When you feel compelled to add a comment, consider rewriting the code to make it clearer.
  • Comments should not be enclosed in large boxes drawn with asterisks or other characters.
  • Comments should never include special characters such as form-feed and backspace.
top

Implementation Comments

Implementation comments are delimited by /*...*/, and //. Implementation comments can be used for commenting out lines of source code or commenting on the particular implementation. These comments are to be read by developers reading your source code. Four styles of implementation comments can be used: block, single-line, trailing, and don’t-compile.

top

Block Comments

Block comments are used to provide descriptions of files, data structures, compound statement and algorithms. Block comments should appear before the code they are commenting. Block comments should be indented to the same level as the code they describe. To set it apart from the rest of the code, a blank line should precede a block comment.

int daysInYear()
{
  int j = 0;


  /*
   * This loop will calculate the number of days in
   * the year.
   */

  for( int days = 1; days <= 365; days++ )
  {
  }
 return days;
}
top

Leading Comments

Leading comments can appear on a single line indented to the level of the code that follows. If a comment can't be written in a single line it should follow the block comment format. We recommend the a leading comment should be preceded by a blank line and followed by an additional // to separate it from the code that follows. Here's an example of a leading comment:

int daysInYear()
{
  int j = 0;

  // This loop will calculate the days in the year
  //
  for(int days=1; days<=365; days++)
  {
  }

  return days;
}
top

Trailing Comments

Very short comments can appear on the same line as the code they describe, but should be shifted far enough to separate them from their corresponding statements. If more than one short comment appears in a chunk of code, they should all be indented to the same tab setting.

if(a == 2) 
{
  return TRUE;            // special case
}
else 
{
  return isPrime(a);      // works only for odd a
}
top

Don't Compile Comments

Comment delimiters can also be used to comment out a line, partial line, or multiple, consecutive lines of code. The use of the // comment style is recommended when you're commenting out several lines of code, but not more. Code commented out with /* */ style comments can cause problems, particularly if another developer attempt to nest /* */ style comments (not all compilers support nested comments). For this reason if you need to comment out a large are of code, we recommend using #ifdef 0 ... #endif.

// good
if(foo > 1)
{
  int x = 5;
  // x++;
  ...
  return x;
}
//else 
//{
//    return false;
//}

// not recommended - be careful
/*if(bar > 1) 
{
  bar++; 
}*/

// bad - nesting not supported on all compilers
/*while(x > 1) 
{
  /* if(bar<1)
  {
    bar++;
  } */ 
}*/


// good
#ifdef 0
for(int i=1; i<10; i++)
{
  // lots of code
}
#endif
top

TODO's

Changes that need to be made, or even suggestions for further work, should be place on single line comments starting with "//TODO:". Both Microsoft Development Studio and code documentation programs can detect these comments, therefore they provide a useful reminder of changes that are still needed in the current development and can also be used to provide recommendations for future work.

//! \todo: Rewrite the fred class
class fred
{
public:           //!< \todo: The following variables should be declared as private
  int size;       //!< \todo: Need to rename this to m_size;
};
top

Code Revisions

Revisions of code must be clearly marked. To identify the contributions from each author we suggest:

for(i=0; i<iNoSim; i++)
{
  ...
  // ***** Version v.nn by Author on dd/mm/yy - START
  ...
  // ***** Version v.nn by Author on dd/mm/yy - END
  ...
}

where 'v' is the version number and 'nn' is the incremental developments within that version; 'Author' is the author of the revision; and 'dd/mm/yy' is the date the revision was made.

Because such code revision marks makes the code less readable it is suggested that they are removed at regular intervals. For example, whenever the version numbers is increase all revision comments should be removed; alternately remove revision marks more than a year old.

top