C++ Program Style, Formatting, and Documentation
Author: Ken Johnson
Date: January 2006
INTRODUCTION
Your program design has three users. The first is the compiler, which requires certain syntax, but does not care about style and comments. The second is the end user who will use your program and receive its benefits. Proper design for this group is important and is termed “usability,” but is not the topic of this paper. The third type of user is any other programmer who will need to understand your design and code in order to maintain it, or a team member who is writing programs which interface with yours. Since most commercially written programs have a very long lifetime, this type user is every bit as important as the others. Learning to properly format and document your work is an essential part of learning the skill of programming, and directly supports these learning themes: Technical Knowledge and its Application; Communications; Leadership and Followership.
Most programming organizations have developed a set of standards to which all programmers must adhere. Some of these involve the use of an automated source code library product (a process called “change management”) which requires tagging every code change with a reason code, a date, and a programmer identifier. At Principia College, we do not need to be this complicated. However, it is important to enforce a C++ standard for two reasons:
Please regard this document as your style, formatting, and documentation standard for C++ programming at Principia College in courses CSCI 171, 181, and 182.
COMMENTING
Provide a prologue (sometimes called “header comments”) which includes at a minimum:
Use in-line comments (sometimes called “block comments”) and sidebar comments (sometimes called “line-by-line comments”) to document the program flow and any code that is complicated. Do not “over-comment” easily understood code. Here is a test for whether the level of detail is correct: Another programmer should be able to find a section of code by reading only the comments, and once there, be able to understand that section by reading both the code and its comments.
In addition, the comments in the heading of a user-defined function deserve special attention because they serve as the “contract” between the calling function and the called function. This standard is described later as part of FUNCTION CALL INTERFACE DOCUMENTATION.
Please study the details of this example of prologue, in-line, and sidebar comments:
// program: ComputeTax.exe
[prologue example]
// version:
2.05
// date: 2003/08/22
// author: J.M.
Smith
// purpose:
compute tax on taxable income
// input: user
inputs taxable income and tax year (cin)
// output: program
displays computed tax (cout)
// assumptions:
taxtable.h is up-to-date
// normal return:
0
// error return:
1 if user failed input stream
#include <iostream> // support for cin/cout [sidebar example]
using namespace std; // eliminate need for scope resolution
#include “taxtable.h”; // current tax tables
float CalculatedTax (float, int); // function prototype
int main()
{
// variable declarations [block comment example]
float fTaxAmount; // computed tax [sidebar example]
char cRepeatFlag = ‘Y’; // initialize to ensure first pass
// outer loop repeats as long as user wishes
while ((toupper(cRepeatFlag) == ‘Y’)
{
… [statements in loop body]
} // while cRepeatFlag [example of documenting end of loop]
// provide final output and return [example of block comment]
cout << “Your tax is: “ << fTaxAmount <<
endl;
return 0;
} // main [example
of documenting end of function]
IDENTIFIERS
Your textbook uses a standard for choosing identifiers – the names of variables, constants, and functions – as described in Appendix F. The Principia College standard does not generally violate the textbook’s standard, but is more restrictive in that we use Hungarian notation.
Hungarian notation indicates the data type as a prefix of the identifier. The purpose is to allow a programmer to always know the type of the variable, constant, or function name without referring back to its declaration. In some programming languages, such as C and assembly language, it is easy to code operations which are inappropriate for a data type, resulting in bugs that are difficult to find. The C++ compiler enforces proper “data typing” in a strong way, so the need for Hungarian notation is not as important for that purpose. However, it is a useful technique for consistency and readability.
The selection of identifiers involves these choices:
What is meant by semantic meaning? The well-chosen identifier is largely self-documenting by indicating its purpose. For example, a variable named fTaxRate is better than fValue1, and a function named ComputePayroll is better than ThisComputation.
All of these choices encourage the programmer to be precise in her meaning. Please study the following examples and the comments describing all of the choices above:
int iCounter; [integer variable - a noun in Hungarian notation]
float fTaxRate; [float variable - a noun in Hungarian notation]
char cGender; [char variable - a noun in Hungarian notation]
bool bIsValid; [bool variable - a verb and condition]
int* piSum; [pointer variable to an integer]
float afTemperature[31]; [array of float variables]
float* apfTemperature[31]; [array of pointers to float variables]
float fMAX_SEATS; [named constant – Hungarian noun, underscores]
class CBankAccount; [class name - a noun]
CBankAccount cbaSavings; [variable of class - Hungarian noun]
void ComputeTax(…); [void function name – normally a verb]
float Mean(…); [value-returning arithmetic function – a noun]
bool Update(…); [value-returning bool function – noun and condition]
It is worth noting that the identifiers of data
members generated by Microsoft Foundation Classes start with m_. These should
be followed by Hungarian notation as shown above.
INDENTATION
When a program is properly indented, the grouping of statements is obvious to the reader, and the nested structures are clear. The braces are paired correctly in the same column. Each level of indentation is generally 4 positions, though the number is not as important as the consistency. When you are using the editor in Microsoft Visual C++, it will assist in proper indentation when you press ENTER at the end of each line. In addition, at any time you can select the entire program (CTRL-A), and then ask the editor to reformat your program with proper indentation by keying CTRL-K followed by CTRL-F. Before finishing your program for submission, please do this.
FUNCTION CALL INTERFACE DOCUMENTATION
A properly designed interface is a call between “functionally cohesive” functions. It serves as the “contract” between the programmer implementing the calling function and the programmer implementing the called function. The documentation answers questions such as these:
Here is the test for the documentation of an interface: The programmers on both sides of the call should be able to implement their programs without ever looking at each other’s implementation, or even having a discussion about it. In C++, this interface documentation can reside in the function heading. The programmer who calls the function has all the information she needs: a function description, pre- and postconditions, and a well-commented argument/parameter list. Here is an example of a properly documented function heading. Would you be able to call this function based on the information provided?
//**********************************************************************
// Function
definition for UpdateSalary
// Description:
updates current salary to new salary on specified date
// Pre: iEmpNum has been assigned and is > 0
// fSalaryChange has been assigned
// cdtCurrentDate has been assigned
// cdtEffectiveDate has been assigned and is>cdtCurrentDate
// fEmpSalary has been assigned and is > 0.00
// Post (normal): fEmpSalary has been updated
and function==true
// Post (error): fEmpSalary is unchanged and function==false
bool UpdateSalary (/* in */ int iEmpNum,
// employee number
/* in */ float fSalaryChange, // amount of
change
/* in */ DateType cdtCurrentDate,// transaction
date
/* in */ DateType cdtEffectiveDate,// date of
change
/* inout */ float& fEmpSalary) // salary
level
{ …
} // UpdateSalary
1. Pre- and postconditions are stated as assertions (true- or false-valued statements), not as general descriptions. The precondition describes the moment of entry to the function, and the postcondition the moment of exit from the function. A postcondition describes what the function has done, not how it does it. Past tense generally is the most precise.
No:
// Pre: The caller must assign values to fAlpha and
fBeta
// Post: This function prints out fAlpha and fBeta
Yes:
// Pre: fAlpha and fBeta have been assigned
// Post: fAlpha and fBeta have been printed
2. The precondition mentions incoming parameters by name, and the postcondition mentions outgoing parameters by name.
void CalcRate( /* in */ float fAlpha,
/* in */ float fBeta,
/* out */ float& fGamma)
No:
// Pre: The first two parameters have been assigned
// Post: fGamma is computed
Yes:
// Pre: fAlpha and fBeta have been assigned
// Post: fGamma == 3.5 * (fAlpha + fBeta)
Special considerations for documenting functions that are members of classes
In C++, support for object-oriented programming is provided through a data type called a class. A class includes both the data and the functions which access the data. Although a program could contain everything about a class and its user, it is common to separate the specification of a class from its implementation. This technique allows all programs that use the class to include the declarations of the class members (data and functions), while the function definitions are implemented only once, and are hidden.
When using classes in C++, the specification file is normally coded as a header file, which is included by both the using program (called the client) and the implementation file.
The specification file should include the following documentation:
The implementation file should repeat the documented parameter list, and include appropriate block and sidebar comments in the function definitions.