Note: These coding guidelines are a part of the book "Computing Concepts with C++ Essentials" by Cay S. Horstmann, published by John Wiley & Sons. They are copyright © 1997, by John Wiley & Sons. All Rights Reserved. Modified 9/6/99 by C. S. Tritt for CS-150.
This style guide may be freely distributed to students in any class that uses "Computing Concepts with C++ Essentials" as a required text. The style guide may be modified for such use, provided that the modifications are clearly marked.
This coding style guide is a simplified version of one that has been used with good success both in industrial practice and for college courses. It lays down rules that you must follow for your programming assignments.
A style guide is a set of mandatory requirements for layout and formatting. Uniform style makes it easier for you to read code from your instructor and classmates. You will really appreciate that if you do a team project. It is also easier for your instructor and your grader to quickly grasp the essence of your programs.
A style guide makes you a more productive programmer because it reduces gratuitous choice. If you don't have to make choices about trivial matters, you can spend your energy on the solution of real problems.
In these guidelines, a number of constructs are plainly outlawed. That doesn't mean that programmers using them are evil or incompetent. It does mean that the constructs are of marginal utility and can be expressed just as well or even better with other language constructs.
If you have already programmed in C or C++, you may be initially uncomfortable to give up some fond habits. However, it is a sign of professionalism to set aside personal preferences in minor matters and to compromise for the benefit of your group.
These guidelines are necessarily somewhat long and dull. They also mention features that you may not yet have seen in the class. Here are the most important highlights:
A note to the instructor: Of course, many programmers and organizations have strong feelings about coding style. If this style guide is incompatible with your own preferences or with local custom, please feel free to modify it. For that purpose, this coding style guide is available in electronic form from the author.
Each C++ program is a collection of one or more files or modules. The executable program is obtained by compiling and linking these files. Organize the material in each file as follows:
Each module starts with a header comment block in the format below.
/***************************************************************** COPYRIGHT (C): 1995, All Rights Reserved. PROJECT: CS 46A Homework #4 FILE: wm.cpp PURPOSE: widget manipulation COMPILER: Borland C++ 3.1 TARGET: IBM PC/DOS PROGRAMMER: Jenny Koo (JK) START DATE: 6/11/95 *****************************************************************/
Below the header comments is an optional notes block.
/* NOTES *********************************************************
General comments go here, for example:
*****************************************************************/
This section lists all included header files.
/* INCLUDE ******************************************************/ #include "iostream.h" #include "ccc.h"
Do not embed absolute path names, e.g
#include "c:\borlandc\include\stdlib.h" /* Don't !!! */
This sections contains constants that are needed throughout the program file.
/* CONSTANTS ****************************************************/ const int GRID_SIZE = 20; const float CLOCK_RADIUS = 5;
This section contains the definitions of classes.
/* CLASSES ******************************************************/ class Product { . . . };
This section contains the definitions of global variables.
/* GLOBALS ******************************************************/ float annual_raise; /* this year's raise for all employees */
Every global variable must have a comment explaining its purpose.
Avoid global variables whenever possible. You may use at most three global variables in any one module.
This section lists all functions of the module. Sort the functions so that all functions are defined before they are called. Use a prototype only in the rare case of a cyclic calling pattern. Put main last.
/* FUNCTIONS ****************************************************/ long dat2jul(int d, int m, int y) /* PURPOSE: Convert calendar date into Julian day RECEIVES: d, m, y - the day, month and year RETURNS: The Julian day number that begins at noon of the given calendar date. REMARKS: This algorithm is from Press et al., Numerical Recipes in C, 2nd ed., Cambridge University Press 1992 */ { . . . } /*--------------------------------------------------------------*/ int main() { . . . }
Supply a comment of the following form for every function.
/*PURPOSE: explanation RECEIVES: argument 1 - explanation argument 2 - explanation RETURNS: explanation of return value REMARKS: preconditions, notes, etc. */
The PURPOSE comment is required for all functions. Omit the RECEIVES comment if the function takes no parameters. Omit the RETURNS comment for procedures (void functions).
long dat2jul(int d, int m, int y) /* PURPOSE: Convert calendar date into Julian day RECEIVES: d, m, y - the day, month and year RETURNS: The Julian day number that begins at noon of the given calendar date. REMARKS: This algorithm is from Press et al., Numerical Recipes in C, 2nd ed., Cambridge University Press 1992 */ { . . . }
No function comment is required for the main procedure.
Parameter names must be explicit, especially if they are integers or Boolean.
Employee remove(int d, float s); /* huh? */ Employee remove(int department, float severance_pay); /* Ok */
Of course, for very generic functions, short names may be very appropriate.
Do not write procedures (void functions) that return exactly one answer through a reference. Instead, make the result into a return value.
void find(vector<Employee> c, bool& found); /* Don't! */ bool find(vector<Employee> c); /* Ok */
Of course, if the function computes more than one value, some or all results can be returned through reference arguments.
Functions must have at most 30 lines of code. The function header, comments, blank lines and lines containing only braces are not included in this count. Functions that consist of one long if/else may be longer, provided each branch is 10 lines or less.
This rule forces you to break up complex computations into separate functions.
Do not define all variables at the beginning of a block. Define each variable just before it is used for the first time. However, list all significant variables and their units at the start of a block in the notes sections of the comments - CST 9/13/99
Every variable must be explicitly initialized when defined, or it must be set in the next statement (for example, through a >> instruction).
int pennies = 0;
or
int pennies; cin >> pennies;
Move variables to the innermost block in which they are needed.
while( /* ... */ ) { float xnew = (xold + a / xold) / 2; . . . }
Do not define two variables on the same line
int dimes = 0, nickels = 0; /* Don't */
When defining a pointer variable, place the * with the type, not the variable, e.g.
Link* p; /* Ok */
not
Link *p; /* Don't */
In C++, do not use #define to define constants.
#define CLOCK_RADIUS 5 /* Don't */
Use const instead.
const float CLOCK_RADIUS = 5; /* the radius of the clock face */
A magic number is a integer constant embedded in code, without a constant definition. You may not use magic numbers in your code. Any number except 0, 1 and 2 is considered magic. (I consider 0, 1 and 2 magic in most cases -- CST)
if (p.get_x() < 10) /* Don't */
Use const instead.
const float WINDOX_XMAX = 10; if (p.get_x() < WINDOW_XMAX) /* Ok */
Even the most reasonable cosmic constant is going to change one day. You think there are 365 days per year? Your customers on Mars are going to be pretty unhappy about your silly prejudice. Make a constant
const int DAYS_PER_YEAR = 365;
so you can easily cut a Martian version without trying to find all the 365's, 364's, 366's, 367's etc... in your code.
Lay out the items of a class as follows:
class Class_name { public: constructors mutators accessors private: data };
All data fields of classes must be private. Do not use friend, except for classes that have no public member functions.
Supply a default constructor for every class.
Always use indentation to show the control structure within your programs. For example,
if (result < 0.0)
{
do some stuff
}
else
{
do some other stuff
}
Remember the compile ignores indentation so your code must be correct as well as correctly indented -- CST
Avoid the if...if...else trap. The code
if( ... ) if( ... ) ...; else { ...; ...; }
will not do what the indentation level suggests, and it can take hours to find such a bug. Always use an extra pair of {...} when dealing with if...if...else:
if( ... ) { if( ... ) ...; else( ... ) ...; } /* {...} not necessary but they keep you out of trouble */ if( ... ) { if( ... ) ...; } /* {...} are necessary */ else ...;
Only use for loops when a variable runs from somewhere to somewhere with some constant increment/decrement.
for (i = 0; i < a.size(); i++) print(a[i]);
Do not use the for loop for weird constructs such as
for (xnew = a / 2; count < ITERATIONS; cout << xnew) /* Don't */ { xold = xnew; xnew = xold + a / xold; count++; }
Make such a loop into a while loop. That way, the sequence of instructions is much clearer.
xnew = a / 2; while (count < ITERATIONS) /* Ok */ { xold = xnew; xnew = xold + a / xold; count++; cout << xnew; }
A for loop traversing a linked list can be neat and intuitive:
for (a.reset(); !a.at_end(); a.next()) cout << a.current().get_name() << "\n";
Don't use the switch statement. Use if/else instead. (I permit the use of the switch statement -- CST.)
Do not use the break, continue and goto statements. Use another bool variable to control the execution flow.
I like to use single line comments (beginning with //) to clearify issues with my code. For example,
// Test for negative term before taking log.
if (result << 0.0) ...
-- CST
The following rules specify when to use upper- and lowercase letters in identifier names.
Names must be reasonably long and descriptive. Use first_player instead of fp. No drppng f vwls (I permit droping vowels -- CST). Local variables that are fairly routine can be short (ch, i) as long as they are really just boring holders for an input character, a loop counter etc... And, do not use ctr, c, cntr, cnt, c2 for five counter variables in your function. Surely these variables all have a specific purpose and can be named to remind the reader of it (e.g. ccurrent, cnext, cprevious, cnew, cresult...).
Use tab stops every 3 columns. That means you will need to change the tab stop setting in your editor!
Use blank lines freely to separate logically separate parts of a function.
Separate functions by comments like /*---------*/.
Use a blank space around every binary operator.
x1 = (-b - sqrt(b * b - 4 * a * c)) / (2 * a); /* Good */ x1=(-b-sqrt(b*b-4*a*c))/(2*a);/*Bad*/
Leave a blank spaces after (and not before) each comma, semicolon, and keyword, but not after a function name.
if (x == 0) f(a, b[i]);
Every line must fit on 80 columns. If you must break a statement, add an indentation level for the continuation:
a[n] = .................................................. + .................;
If this happens in an if or while, be sure to brace in the next statement, even if there is only one.
if( ......................................................... and .................. or .......... ) { ... }
If it wasn't for the braces, it would be hard to visually separate the continuation of the condition from the statement to be executed.
Opening and closing braces must line up, either horizontally or vertically.
while (i < n) { print(a[i]); i++; } while (i < n) { print(a[i]); i++; }
Some programmers dont line up vertical braces but place the { behind the while.
while (i < n) { /* Don't */ print(a[i]); i++; }
But that makes it hard to check that the braces match. Other programmers place the { in a line all by itself. That isn't a good idea because it wastes a line of precious screen space. (White space is good. Plus the Visual C++ expects the following form -- CST).
while (i < n) { /* Do - CST */ print(a[i]); i++; }
The trick is not to leave a blank line after the opening brace but to type a tab followed by the first line of the loop body.
Some programmers take great pride in lining up the names of structure fields.
class Employee { private: string name; int age; float hourly_wage; Time hiredate; };
This is undeniably neat, and we recommend it if your editor does it for you. But don't do it manually. The layout is not stable under change. A data type that is longer than the preallotted number of columns requires that you move all entries around.
Some programmers like to format multiline comments so that every line starts with **.
/* This is a comment ** that extends over ** three source lines */
Again, this is neat if your editor has a command to add and remove the asterisks. Otherwise, it is a silly thing to do since it is a powerful method of discouraging programmers from editing the comment. If you have to choose between pretty comments and comments that reflect the current facts of the program, facts win over beauty.
It has been said that all usage of the preprocessor points to deficiencies in the programming language. C++ fixes some deficiencies. Do not use #define for constants or macros--use const and inline instead.
Do not use the #define facility to make your code like Pascal,
#define begin { #define end } #define repeat do { #define until( x ) } while( !( x ) );
Neat as they may be, these constructs are strictly outlawed. Your fellow programmers have better things to do than play preprocessor with your code.
A legitimate use for the preprocessor is conditional compilation (e.g. #ifndef NDEBUG ... #endif).
To comment out a block of code that may itself contain comments, use #if 0 ... #endif. (Recall that C++ comments do not nest.)