PROGRAM STYLE AND DOCUMENTATION STANDARD

The following represents a consensus of several classes for the standards for all program projects. (Nightly homework could use a lesser standard, but don't forsake all your good habits!) These standards have been slightly modified to conform with the automatic style of Visual C++. Programs that fail to conform to this style will be returned for repair, marked down, and/or gazed upon with narrowed eyes by your peers.

Note: Ken Johnson has developed a refinement of this standard that is now used for CS 171 and CS182 classes. This is an excellent and professional document and is made available for your interest. If you have a question about a particular style or documentation point, Ken's Programming Style may answer it.

Help on reading your graded/returned projects.

The standard is outlined in the following paragraphs. A sample program is given below to illustrate some elements of the standard. Please keep this standard for handy reference. (Even in our "paperless" class, this web page might be legitimately printed for convenient reference.) Thanks to earlier students for all their contributions.

1) The appropriate header file (usually SomethingDlg.h) must contain:

program name, author name, date, description of the program,

brief description of inputs and outputs, assumptions, normal program function,

error conditions and return codes,

time log for your work on the program,
what help you received from others and what help you gave to others during this project. (This is a sort of bibliography for the program.)
It should also include test results, sample output, etc. unless these are supplied separately (as they are in the Compilers class).

In classes like the Compilers class, the Dlg.h file should indicate where test results, etc. may be found.

These elements might be surrounded by conditional compilation markers (#if 0 and #endif /* 0 */). For example:

    #if 0 
       This program produced the following output:

        16 19 19 23 22 13 14  9  5  4 12  7
        29 32 42 37 30 26 24 19 10 11 16 10
    #endif /* 0 */

In Windows projects, this information should be included in the header file for the Dialog class. (This has a name like CompileDlg.h.)

In DOS or Console projects, this information should be included in the file that contains "main()".

2) The order of program elements for header files (*.h) is #includes's, #define's, class definitions, inline functions. For implementation files (*.cpp), the order is #includes's, #define's, function prototypes, main(), other function definitions. Classes are organized as follows: public member data, public member functions, private member data, private member functions. The function definitions in the .cpp files should be in the same order as their declarations in the class declaration. Names should follow the conventions of the examples below.

3) Opening and closing braces are aligned (unless the entire braced block fits on one line). Indent 1 tab (4 spaces) for a block of code within a loop. Indent 1 tab for all code inside a class, a function, or main. Feel free to use automatic Visual C++ formatting (CTRL-A, CTRL-K, CTRL-F).

4) A class description precedes each class declaration. A function description with pre- and post-conditions is part of each function declaration or prototype (usually inside the class declaration). These are copied into the implementation files (*.cpp) also.

5) A comment is given for every constant and variable next to its declaration. The comment should explain the use of the constant or variable. If variables are utterly trivial (loop control variable), this may be omitted.

6) Class member data starts with "m_". This distinguishes it from formal parameters and local variables.

7) Symbolic constants, enumerated types, or declared constants are in all UPPERCASE. Variables should use upper- and lowercase as shown below. Identifiers should clearly indicate the usage of the item identified. Use Hungarian notation to indicate the type of variables.

Examples:

    bool     bLapsCompleted, m_bFirstCall; // b means boolean.
   int      iRowCount, aiPixelCount[100]; // ai means array of integers.
   int      *piColCount;        // pi means pointer to integer.
   long     lHits;              // l means a long integer (up to two billion).
   char     pszFirstName [255]; // psz means pointer to string with zero termination.
   char     cMenuChoice;        // note the difference between char and array of char.
   CString  m_csLastName;       // member variable (m_) that is a CString.
 
   void CWalker::SetPosition (int iNewRow, int iNewCol) // formal parameters are treated the same as local variables.
 

8) Class identifiers begin with C. Other type names (such as typedef structures) should end with "_t". This convention is borrowed from widespread standards. The time structure in the Standard Library is "time_t" and the size type is "size_t".

9) Operators are generally surrounded by spaces (i = i + 2).

10) In two-dimensional arrays, rows are first, columns second.

11) Don't redefine or reinvent constants and functions that already exist. For example, this means that you should use CHAR_BIT if you wanted a constant for the number of bits in a character. Use RAND_MAX for the largest possible random number returned by rand(). Use toupper() to transform characters to uppercase. Use isalpha() to test for alphabetic characters. Use isalnum() to test for alphabetic or numeric characters. Use atoi() to convert alphabetic information to integers, and so forth. You should not rewrite these functions. Such re-writing wastes time and invites platform-centric errors.

12) Minimize the scope of variables. This is always wise. It makes the program less error-prone and easier to read.

13) Loops and functions should have one exit point unless this obscures the logic of the loop or function. This is less important if the loop or function is small (10 lines or so).

14) Always free memory (often with destructors) when you are done with it. Memory "leaks" are a frequent and pernicious side-effect of poor programs. When a class requires allocated memory, the programmer is responsible to manage memory correctly in construction, copy construction, destruction, and assignment operator.

15) When a program is complete: (1) Remove all files from the debug directory except the executable (which ends in ".exe"). (2) Rename the project directory with your last name prefix and the week number (for example, "full3" for Week 3). (3) Drop the project directories (with sample files) into:

\drops\cs380\

Be careful. The network time stamp is applied to programs as they are dropped. "Network time" can differ from actual time by a couple minutes.

Here are some examples of the standards in a program:

<beginning of "main file" TomPileDlg.h>

/******************************************************************************
Program Name: TomPile
Authors:      Tom Fuller and John Hooper

This program (and the CS 380 course itself) owes a huge debt to John C Hooper.

Hoop put dozens -- possibly hundreds -- of hours into the Unix version of this
compiler between 1987 and 1994. Tom Fuller added dozens of hours -- largely in
making it object-oriented (Unix C++ in 1996). Tom invested perhaps
a couple dozen hours more to port it to Windows Developer Studio in 2000 and 
then to .NET (Windows XP Pro) in 2006.

Date: March 24, 2006

Inputs: Modula-2 source code, MASM 6.11 with library files io.mac and io.obj
Output: executable console program that performs the actions indicated by the source code

Assumptions: This code uses C++ in the .NET environment. Properties should be set to 
   use MFC code as a statically linked library. This code assumes
   that the Standard Template Library is available in .NET. It assumes that the user
   has read, write, and execute permissions in the appropriate directories.

Error messages: Detectable errors are displayed with AfxMessageBoxes and detailed
   information about where in the source code and/or compiler code the error was
   detected. Undetectable errors may result in unseemly behavior (crashes, etc.).


TOM PARTIAL TIME LOG

The following was done May-June 2002:

   Build attractive dialog window        2  hrs
   Adapt DOS console code to dialog      4 

/************************************************************************\
* INCLUDES *
\************************************************************************/
#include <iostream>
 
<end of "main file">

<beginning of another file, "random.h">
 
class CRandom 

// The CRandom class is used instead of the built-in random functions to allow
//    exact reproducibility of results. It maintains a seed which is updated
//    with every call to the object. It produces pseudo-random numbers (within 
//    various ranges) and random fractions between 0.0 and 1.0. It uses the
//    linear congruential method to generate the pseudo-random numbers.

    // The object may be used in five ways:
    // Set the m_lSeed to some value.
    // Get a pseudo-random integer >= 0 and < MODULUS.
    // Get a pseudo-random integer >= 0 and <= "limit".
    // Get a pseudo-random integer >= <= two limits.
    // Get a pseudo-random fraction between 0.0 and 1.0.
    //
    // The member functions implement these uses.
    // The three constants and the basic linear congruential formula
    //    were supplied by Clint Staley (Prin '80).

{
public:
    // There are two constructors.
    // An object of class CRandom can be constructed with m_lSeed specified,
    // (the second constructor), or with no parameters (setting m_lSeed to 1).
    CRandom() { m_lSeed = 1; };

    Crandom (long lInSeed) { m_lSeed = lInSeed; };

    // destructor (not elaborated since no memory is allocated by this class)
    virtual ~CRandom() {}

	//**********************************************************************
	// Function: Set
	// Description: Set internal seed to the input.
    // PRE:  lInSeed is set to a valid long.
    // POST: The random seed is set to lInSeed.
    void Set(long lInSeed) { m_lSeed = lInSeed; }

	//**********************************************************************
	// Function: GetRandInt
	// Description: Get a pseudo-random integer >= 0 and < MODULUS.
    // PRE: none
    // POST: The random seed is set to a new "random" value and returned.
    long GetRandInt () 
	{ 
        m_lSeed = ((ARAND * m_lSeed) % MODULUS + CRAND) % MODULUS;
        return m_lSeed;
    }

	//**********************************************************************
	// Function: GetRandIntRange
	// Description: Get a pseudo-random integer between two limits (possibly including the limit values).
    // PRE: none
    // POST: The random seed is set to a new "random" value. A "random" value >= lLowerLimit
    //    and <= lUpperLimit is returned.
    long GetRandIntRange (long lLowerLimit, long lUpperLimit);

private:
    long m_lSeed; // This random seed is changed with every call to this class.

    // Pseudo-random implementation constants.
    enum 
	{ 
        MODULUS = 65536L, // 16th power of 2 (2^16).
        ARAND = 25173L,   // multiplier chosen to work correctly with 2^16.
        CRAND = 13849L    // addend chosen to work correctly with 2^16.
    };

}; // class CRandom 

<end of "random.h">

Last revised: 24 March, 2006 4:01 PM