Coding guidelines are used by programmers to make their code readable. Whenever you write a program it's important to have a set of coding guidelines to follow. Two of the main advantages to following a set of coding guidelines throughout the lifetime of a program is that it makes it easier to maintain the program and it allows new developers to become acquainted with the program faster.
Coding guidelines are of great importance when several developers are working on the same project. Without them the program has very little consistency and the job of maintaining the program becomes much harder. Studies have estimated that approximately 70 percent of the money spent on a program over its lifetime is for maintenance. So you can imagine companies want their programs to be as maintainable as possible.
Documentation guidelines are one of the most important aspects of writing maintainable code. These guidelines refer to placing comments in your source code. It's very important to comment your code as you go along. Do not wait until you are finished programming to go back and comment everything. There's a good chance that you will have forgotten what your code does and instead of relearning it you'll write useless comments that provide little or no help. Each program you submit should contain comments as described in the following sections.
Each source code file should have a header at the top of it containing the following information:
The following is a sample source code header:
//==================================================================== // // Program Name: Sorting Names with Insertion Sort // Assignment: 1 // Date: September 14, 2002 // // Programmer: Nomed Nocaed // Course: CSC 112 B Professor: Nirre Pluf // // Program Description: // This is a little program that reads a list of names from // a specified file or from standard input and then sorts // the names in ascending order and prints them to standard // output. // // Command line arguments are used to specify where the // list of names should be read from. If the program // doesn't receive any command line arguments then it reads // the names from standard input. If the program receives // a single command line argument then it reads the names // from the corresponding file. If more than one command // line argument is specified the program prints a usage // message and terminates. // // Input: // List of names from standard input or specified file // // Output: // Sorted list of names to standard output // // Assumptions/Limitations: // It's assumed that the length of a name will not exceed // 40 characters and that the number of names will never be // more than 5,000. // //====================================================================
Major loop and conditional statements should be commented in most cases. You should place the comment before the code and it should be indented at the same level as the code. Comments within braces should be indented at the same level as the statements within the braces.
The following is an example:
// Set minimum to the smaller of x and y if(x < y) { minimum = x; } else { minimum = y; }
Every function should have its own header. The header must indicate the pre- and post-conditions of the functions. The pre condition states what must be true before the function executes (state of the program which the client guarantees will be true before calling this function). The post conditions describes what is true after the function executes (state of the program the function will provide when it returns).
The following is an example:
//==swap============================================================== // pre: a and b contain two integer values // post: values of a and b are exchanged //==================================================================== void swap(int& a, int& b) { ... }
//==cStrLength======================================================== // pre: s must be a char array containing a proper c-string // post: returns the length of s (minus null) as an integer //==================================================================== int cStrLength(char *s) { int n = 0; // counter for the number of characters // count characters until null is reached for( ; s[n] != '\0'; n++); return n; }
Every variable and constant identifier should be commented when it is declared. You should place a comment describing the variables purpose after it's declaration, on the same line.
The following are examples:
int movieFrame[100]; // Array of MPEG frame sizes (bytes) int numFrame; // Number of MPEG frames in array
Style guidelines are just as important as documentation guidelines when it comes to writing maintainable code. These guidelines refer to whitespace usage and identifier names.
You should always use descriptive identifier names for objects, functions and classes. For example the identifier numberOfNames is more descriptive than n. If an identifier consists of more than one word the first letter of each word should be capitalized. You should not use underscores between words. The following is a list of rules for the various types of identifiers:
You can write sloppy unreadable code with C++ unless you use whitespace correctly. If you consistently follow the guidelines below on whitespace usage your code will be easier to read and debug.
You should never use tabs to indent your code. Using the above rules the C++ control statements have the following format:
if(booleanExpression) { ... } else { ... }
switch(integerExpression) { case constantExpression: { ... break; } default: { ... break; } }
for(expression; expression; expression) { ... }
while(booleanExpression) { ... }
do { ... } while(booleanExpression);
In general you should try to keep the size of your functions and member functions to be less than 40 lines of code. Large functions are hard to understand and debug.
Since C++ is an object-oriented language you will spend a lot of your time writing classes. Some of the guidelines for classes have are ready been discussed. This sections describes the remaining guidelines.
Inside a class definition the declarations of members should be indented 3 spaces. Access control sections should be defined in the order public, protected and then private. This order corresponds to the "interest" level of the section. In general more people are interested in the public section of your class than the private section. The following is an example of a class definition:
//==IntegerStack====================================================== // Class of objects which maintain a stack of integers //==================================================================== class IntegerStack { public: // Default constructor IntegerStack(int size = 64); // Copy constructor IntegerStack(const IntegerStack& s); // Destructor ~IntegerStack(); // Answer top element and pop it off int pop(); // Push the specified element on top of myself void push(int element); // Answer true iff I'm empty bool isEmpty() const; // Assignment operator IntegerStack& operator = (const IntegerStack& s); protected: private: int* elements_; // Pointer to an array to hold my elements int size_; // Size of my element array int top_; // Index of where the next element will be pushed };
You should structure your classes so they can be reused in other programs. One idea that helps is to put your classes in two files called the specification and implementation files. The specification file contains the class definition while the implementation file contains the definitions of the class members. For example consider the IntegerStack class from above. The definition for this class would be in a file named integerStack.hxx and would appear as follows:
#ifndef INTEGERSTACK_HXX #define INTEGERSTACK_HXX //==IntegerStack====================================================== // Class of objects which maintain a stack of integers //==================================================================== class IntegerStack { public: ... private: ... }; #endif
The implementation of the IntegerStack class would be in a file named integerStack.cpp and would appear as follows:
#include "integerStack.hxx" //==default constructor=============================================== // pre: size is a postive integer value for the stack size, // default size is 64. // post: new empty stack created of size size, top initialized to 0 //==================================================================== IntegerStack::IntegerStack(int size) { top_ = 0; size_ = (size > 0 ? size : 64); elements_ = new int[size_]; }
You should also include a header as described in the documentation guidelines in both of these files.
You should never have a public data member in a class. If you need to provide access to a data member then you should do it with a getter/setter pair of member functions. For example:
// Answer my current size int size() const; // Change my size void size(int s);
Remember that the default copy constructor and assignment operator perform a "shallow" copy or a bit-by-bit copy. This is fine for some classes but whenever your class contains a pointer there is a very good chance that you will need to write your own copy constructor and assignment operator to perform a "deep" copy.
Send comments to fulp@wfu.edu
Last modified on 8/27/2002