|
CET 375: Data Structures & Algorithms
Professor:
Ricky J. Sethi
|
|
|
Sethi Family HomePage
Programming Style Sheet
Source Code Documentation & Naming
- Opening Documentation: the header block should include
the following:
- Program name/syntax
- Description of what the program does
- Summary of the problem's specifications and assumptions
- License info (optional)
- References to sources of additional information used
- Parameters
- Class/Program Invariant (ensure these conditions are true)
- Algorithm(s) used (including any special notes)
- Output (any print statements, files created, etc.)
- Return values (does it return any parameters?)
- Name of the authors (plus contact info)
- Creation & modification dates
- To Do Items (optional)
Sample:
/*********************************************************************
*
* PROGRAM: foobar
* SYNTAX: foobar <param_1>
* DESCRIPTION: This program does foobar on param_1
*
* LICENSE: ---OPTIONAL---
* ****************************************************
* GPL & Postcard-Ware! This program is distributed
* under the standard GPL and is freely useable or
* distributable as long as this license is attached.
* ****************************************************
*
* SPECS: Program's specifications and assumptions here
* REFERENCES: Original idea based on emacs
* PARAMETERS: Uses following parameters:
* - <param_1>: integer, used to determine iterations
* ALGORITHM: Pseudocode describing the algorithm here
* INVARIANT: Class or program invariants (verify state of class) here
* OUTPUT: foobar automagickally creates:
* - data.txt (contains guest data)
* - log.html (entries' log file)
* - Prints diagnostic messages to STDOUT
* RETURN: Returns return_int code to indicate successful conclusion
*
* AUTHOR(S):
* Ricky J. Sethi (rickys@sethi.org)
* http://www.sethi.org/
* MODIFICATIONS:
* Created by Ricky J. Sethi on 2003-03-07
* Modified by Ricky J. Sethi on 2003-03-08
* Modified by John Q. Public on 2003-03-11
* TODO: ---OPTIONAL---
* * Add new icons
*
*********************************************************************/
- Each subprogram should contain all of the following:
- Function name/syntax
- Description of what the function does
- References to sources of additional information used
- Precondition: the state of the object before this fxn is called
- Receive: implicit and explicit parameters
- Return: implicit and explicit returns
- Output: anything it might print out or display
- Postcondition: the state of the object after this fxn is called
Sample:
/*********************************************************************
*
* FUNCTION: foobar(<param_1>)
* DESCRIPTION: foobar() does foobar on param_1
* REFERENCES: Original idea based on emacs
* PRECONDITION: A stack has been defined
* RECEIVE: Uses the following EXPLICIT parameters:
* - <param_1>: integer, used to determine iterations
* Uses the following IMPLICIT parameters:
* - the stack itself
* RETURN: foobar() EXPLICITLY returns:
* - return_int, a reference to an int
* foobar() IMPLICITLY returns:
* - the modified stack
* OUTPUT: Prints a "FULL STACK" message if no space available
* POSTCONDITION: The new element has been added to the stack
*
*********************************************************************/
- Comments should be used to explain key code segments and/or
segments whose purpose or design is not obvious. Use comments
liberally to explain non-trivial code. When possible, align
comments to the right of the code segment as in the following
sample (such code can be read without comments by looking only at
the left side of the page):
static int j = 0;
if (j++ == 0) // Guard against cerr allocating memory
cerr << "Out of memory\n"; // Tell the user
abort(); // Give up now...
- All methods and data members in a class declaration are
required to be prefaced with
single line comments describing the purpose of the member. For
example:
class CVXFoo {
...
// registers the foo factory interface
void RegisterFactory(CFooFactoryInf* pFact);
...
// factory interface used to allocate new foos
CFooFactoryInf * m_pcffiFooFactoryPointerMember;
};
- Use formatting comments to separate functions and related
sections of the code (see Class Member Organization).
- All functional code must be clearly commented to indicate
exactly what the code is doing. Any numerical calculations
should have descriptive comments stating the purpose of the
calculations
- In general, there should be sufficient documentation to
understand the method logic without having to read the
executable code.
- Separating Source Members: Class declarations and
definitions/implementations should be contained in separate
files. All source members should assume the follow the naming convention:
- <descriptor>.h
- <descriptor>.cpp
- <descriptor>.c
where the <descriptor> does not contain spaces or
strange characters (use the underscore character
("_") to separate words) and the first word should
always start with a lowercase letter.
Appearance of code
- Put each statement on a separate line.
- Class Member Organization: The "interface" of the class
should be given last. That means the data member declarations
should be made first followed by class method declarations.
Generally, methods and data members should be
organized by security in the order of private, protected, and public.
class CFoo : public CFooBase {
// attributes
//-------------------------------
private :
protected :
public :
// methods
//-------------------------------
private :
protected :
public :
};
- Put each
{ and } on separate lines and
align the corresponding braces.
- Indent the statements enclosed by
{ and }.
- When a statement is continued from one lie to another, indent
the continued line(s). Align the identifiers in each constant and
variable definition, placing each on a separate line. For
example:
const double TAX_RATE = 0.33,
INTEREST_RATE = 0.195;
int employeeNumber;
double hours,
rate,
wages;
- Use blank lines and spaces liberally between declarations and statements
and also between blocks of statements to make the program
structure clear.
- Label all output produced by a program. For example:
cout << "Employee # " << employeeNumber
<< " Wages = $ " << employeeWages;
Instead of this:
cout << employeeNumber << " " << employeeWages;
Naming & syntactical guidelines
- Put identifiers for constants in uppercase, separating words by
underscores (
"_"), as in
const int TAX_RATE = 33;
- Put identifiers for variables in lowercase, capitalizing the
first letter of each subsequent word or separate the words
with underscores (
"_"). For example, either
int totalHoursWorked;
or
int total_hours_worked;
- Method/Member Function Naming: Put identifiers for types and functions
in lowercase, but capitalizing the first letter of each word after
the first one.
Special characters such as dashes and underscores are prohibited.
The method name chosen should be descriptive of the method
functionality. For example:
displayInfo()
- Class Naming: All class names should begin with "C" and
all words should begin with a capital letter. The class name
should be descriptive of the class intention(s). For example:
class CFooBar : public CFooBarBase
- Data Member Naming: Use meaningful identifies (e.g.,
"wages = hoursWorked * hourlyRate;" instead of
"w=h*r;"). Don't use "skimpy" abbreviations just to
save a few keystrokes when entering the source code. All data
members should assume the following format:
[m_]<type><identifier>
where [m_] indicates class member data,
<type> is a data type prefix and
<identifier> describes what the data
represents. The identifier should always begin with a capital
letter. The conventions for data type descriptors include:
short int |
i |
long int |
l |
float |
f |
double |
d |
bool |
b |
CString |
str |
char |
c |
char* |
sz |
pointer |
p |
enum |
e |
CSomeClass |
c<first_letters_of_each_word> |
Examples:
unsigned short |
m_iMaxRetries; |
long |
m_lNumberOfRows; |
float |
m_fPercentComplete; |
double |
m_dCountResult; |
bool |
m_bCacheItemsYN; |
CString |
m_strName; |
char |
m_cSwitchType |
char * |
m_szLogBuffer; |
int * |
m_piState; |
eObjectType |
m_eFirstObjectType |
CSomeClass |
m_cscObjectOfSomeClass |
Declaration file guidelines
- Include Guards: All class definition and interface source
members must have a preprocessor include guard to prevent
compilation errors due to accidental multiple includes. The
include guard should come just before the Comment Header. The
scope should include all the entire contents of the. The #endif
directive should be the last line in the module. Example:
#ifndef _FOOBAR_H
#define _FOOBAR_H
. . .
some source code
. . .
#endif // _FOOBAR_H
- Header Includes: Class header files should include only
headers that are required for the class definition. Headers
should not be included as a convenience or "shortcut" to
automatically include resources for other source members.
Headers should only be included for the following reasons: to
provide class definition of super class(es) or to provide class
definitions for other classes referred to in data members and
methods.
- Inline Methods: Inline methods should only be used under
unique circumstances. These are typically used for operations
that are called frequently and would otherwise present
performance issues. Inline methods in general should be avoided
because they will introduce build dependencies when the behavior
of the inline method is changed.
Good programming habits/guidelines
- All method parameters should include an argument name following
the type. This helps to identify the purpose of the parameters.
It is helpful to identify the directional usage of parameters with
"in" and "out" name qualifiers. If possible, "in" parameters
should be passed as a
const reference (or
pass-by-value) to prevent accidental data
changes. All class instances should be passed as references (&)
where possible. Examples:
BOOL CopyTables( const CPList& inTables, CPList& outTables);
BOOL CopyMoreTables( /*in*/ const CPList& curTables,
/*out*/ CPList& newTables);
- Variables and Parameters: All local and global variables
should always be initialized when declared. All variables and
parameters should have a meaningful name and must begin with a
type prefix (see Data Member Naming). Examples:
BOOL bForceYN = FALSE;
CString strName = "John";
ObjectId lObjectID = NEW_ID;
- Arithmetic: All arithmetic code should include
validations for numerical exceptions. This includes trapping the
following conditions:
- Divide by zero
- Data type overflow
- Boundary conditions
- Memory Management: If at all possible, try to avoid heap
memory allocation for data members. Whenever temporary memory is
required for the scope of some function, use stack allocated memory
rather than heap allocated. This will ensure reliable
cleanup upon exiting the scope of the function (even when
exceptions are thrown). And, it's less code to manage. Example:
//heap allocated aproach is risky
CFoo * pcfObj = new CFoo();
pObj->SomeMethod( pcfObj );
delete pcfObj;
//stack allocation approach is safer
CFoo cfObj;
pObj->SomeMethod( &cfObj );
- Use a modular approach for a complex problem. Don't
write one giant subroutine.
- Use the basic control structures when developing each code
segment. Any program unit can be written using only the
sequential, selection, and repetition structures.
- Use local variables within subprograms. Declare
variables near their first use (not in C programs, though).
Declare the constants, on the other hand, at the beginning of a function.
- Avoid using global variables to share information between
subprograms. Instead, use parameters to pass information.
- Use constants instead of "magic numbers". I.e., use
BIRTH_RATE instead of the actual number
38573.
- Identify any pre-conditions and post-conditions a program or
sub-program has and check them. The
assert()
mechanism should be used to check pre- and post-conditions.
- Strive for simplicity and clarity! Clever programming
tricks intended only to demonstrate the programmer's ingenuity or
to produce code that executes only marginally more efficiently
should be avoided.
Helpful Programming Techniques
- Manual Debugging Techniques: when using the following debugging
techniques, take care to put such temporary output statements in
places that are helpful in locating the source of the error and
not use so many of these statements that the volume of output
hinders the search for the error.
- Use a dbg() function to display error codes:
void dbg(String msg) {
cout << msg << endl;
}
The advantage to using a debug() function to announce errors is
that once you're done debugging, you can simply comment out the
cout statement without having to hunt down each instance of error statements.
- For more localized debugging, use a global variable
$DEBUG which you can then implement with a simple if
statement:
if ($DEBUG) {
cout << msg << endl;
}
- Commenting out regions of code: often, you run into the
problem of commenting out huge blocks of code that already
contain comments. How can you comment out regions of code
with nested comments (especially if you use C-style comments)?
Just enclose it in an if statement; for example:
if (false) {
/* Other code comments */
. . .
}
- Use a stub function statement in each method or
subroutine to announce itself and also to include pseudocode in
comments describing what that method will do. For the announcing,
use the dbg() function you used above. A sample
stub would be:
int ComputeInterestPaid(int iRate) {
dbg("ComputeInterestPaid("+ iRate +")");
/* ComputeInterestPaid does this:
1. Get the (global variable) principal
2. Get the interest_rate
3. Compute Interest Paid
*/
}
- Use templates (with sections for constructors, accessors,
mutators, etc.) (examples to come)
Course Notes & Guidelines: All lower case!
- Program submission naming guidelines/protocol:
project<project_no>_group<group_no>_<type_of_file>.<file_extension>
So, for example, if Group 1 was submitting their first project,
they'd submit it as follows:
project01_group01_specs.txt
project01_group01_flowchart.gif
project01_group01_header1.h
project01_group01_program1.cpp
Please Note: Text files should be plain text files;
i.e., if you use MS Word to create your specifications file,
choose "Save As" and then choose "Plain Text". An alternative is
to use Notepad (shudder!) or download a copy of Emacs for Windows
or Linux from http://www.gnu.org/software/emacs/windows/faq2.html#where-precompiled
and use that (recommended). Also, the Flowchart files should be
submitted in GIF or JPG formats.
- Program submission emailing guidelines/protocol; email address:
cet375_submissions@sethi.org
- Program submission emailing guidelines/protocol; email subject:
<assignment-name>_<last-name>_<first-name>
So, for example, if I was submitting my first project, I'd submit it as follows:
project01_sethi_ricky
Misc Links/Notes
- Course Tutorials & Links:
- Unix Tutorials & Links:
- Links to coding standards & styles:
- Guide to writing/compiling Visual C++ programs:
- Misc Programming Links:
|