C++ Programming Style Guide
This style guide is mandatory for all submitted work for grading
(homework, projects, labs, exams). The purpose of the guide is
not to restrict your programming but rather to establish a
consistent style format for your programs. This will help you debug
and maintain your programs, and help others (including your
instructor) to understand them. As your programs grow in length and
complexity, it is critical to use a consistent style. In the long
run this will help you since one focus of this course is to build a
foundation for later courses. Points will be deducted from
submitted work that does not conform to this style guide.
Visual Layout
"Whitespace" refers to newlines, space characters and tabs.
In source code we do not generally use tabs — in fact,
emacs replaces tab characters with an appropriate number of
space characters. In many circumstances whitespace is not
required in order for compilers to correctly compile source
code, even though the result is unreadable to us. For
example, the following is a perfectly valid program:
| Bad Formatting |
|
Good Formatting |
#include <iostream>
using namespace std
;int main(){int x,y
=1;cin>>x;while(x>0
){y=2*y;x--;}cout<<
y<<endl;return(0);}
|
|
#include <iostream>
using namespace std;
int main() {
int x, y = 1;
cin >> x;
while( x > 0 ) {
y = 2*y;
x--;
}
cout << y << endl;
return(0);
}
|
... but pretty hard to read. There are three major ways we
use whitespace to format code for maximum clarity:
- Whitespace separating elements of code:
Consistent use of whitespace
transcends blank lines and indentation, it also looks at how
spaces are used to separate elements of a line of code. The style guide
recommends whitespace between operators and operands, except
where precedence is highlighted by leaving out spaces.
| Good |
y = 2*y + x/y + 5; |
if( y >= 2*y - 5 && x*y <= 24 ) |
| Bad |
y=2*y+x/y+5; |
if(y>=2* y-5&&x * y<=24) |
- Blank Lines:
In source code, use blank lines to separate
chunks of code that accomplish distinct tasks.
While to some extent this is taste and art, you should expect
distinct functions to be separated by blank lines, and a long
function body should usually be broken into chunks by blank
lines as well.
- Indentation:
Indentation highlights the block structure of programs, much
as it does in formatting outlines. Each level of block
nesting must be indented by a consistent number of spaces
(two in the emacs settings we provide you). New levels of
indenting are introduced by function bodies, for, while and
do-while bodies, the then and else blocks of an if
statement, and struct definitions.
Curly Braces, i.e. { }'s
Curly Braces, i.e. { }'s in C++ are used to create a "block"
from one or more statements. The delineate the bodies of
functions, loops and switch statements, struct definitions, and
the then and else blocks of if statements. Generally, one should
either always put the opening curly brace on a new line
(preferred for this course) or always but it last on the
previous line. Once again consistency is key. If the opening
brace goes on a new line, the preference for this course is to
keep the previous line's indentation — i.e. do not indent
the curly brace. Generally, curly braces of either kind will
occupy their own line, except for rare occasions when an entire
block is put on one line. The exception is that comments may
follow either opening or closing braces.
| Good | Good | Bad | Bad |
while( x < 3 ) {
cout << x << ",";
x++;
}
cout << endl;
|
while( x < 3 )
{
cout << x << ",";
x++;
}
cout << endl;
|
while( x < 3 )
{ cout << x << ",";
x++; }
cout << endl;
|
while( x < 3 )
{ cout << x << ",";
x++;
} cout << endl;
|
Comments
Comments should be indented consistently with the block of code they
describe. Comments can be divided into two general categories,
strategic and tactical.
- Strategic comments are used to give the reader a
general overview of what is going on. These comments appear at the
beginning of files, before important functions, and above
important blocks of code. Strategic comments tend to be written in
sentences with an emphasis on explaining the big picture of what
the block of code is designed to do.
- Tactical comments are designed to explain tricky areas
of code, what parameters do, and hints about the control flow of
the program. These comments should be intermixed in the code when
needed. They should be shorter than strategic comments, in bullet
format, and may be in inline format. One should, for instance,
place a tactical comment next to the statement that assigns a
fixed, non-obvious value to a variable.
The following example shows good commenting. Note the tactical
comment about why "9.0" is used instead of "9".
/***************************************************
Fahrenheit to Celsius Conversion
***************************************************/
#include <iostream>
using namespace std;
int main() {
// Read temperature in Fahrenheit
double Tf;
cout << "Enter temperature in Fahrenheit: ";
cin >> Tf;
// Compute temperature in Celsius
double Tc;
Tc = (Tf - 32)*(5/9.0); // .0 forces division as double
// Write temperature in Celsius
cout << "That is " << Tc << " degrees Celsius."
<< endl;
return 0;
}
Naming
Variables should have meaningful names. For example,
consider a program that uses a variable to track the yards per carry
of a football game. Such a variable should be called
yardsPerCarry
vice ypc for program readability. This must be balanced against
using names which are too long, which can obscure the code. (Fifteen
or so characters approaches the “too long” limit.)
It should be mentioned that this is most important for variables
that have large scope — i.e. they are visible and need to be
used either from different files or from widely separated lines in
the same file. The code example above seems to violate this rule,
but variables Tf and Tc only a appear, and
are only in scope, within less than a dozen lines of code, and in
the context of those few lines they are descriptive enough. Also,
because this is an example embedded in a document, compactness of
the code is very important.
Single letter variables or constants should not be used with the
following exceptions. An exception to this rule is when it is common
practice to identify something with a single letter. An example of
this is the coordinate system (x, y, and z). A second exception
occurs in the use of loop counter variables where it is common
practice to use variables like i and j as counters in for loops.
Function names and variable names should begin with a lower case
letter. An identifier consisting of multiple names SHALL have each
name distinguished by making the first letter of each name part
(after the first)
upper case (e.g. yardsPerCarry) or by using underscores
(yards_per_carry).
The former method is strongly encouraged.
Constants should be named in all upper case
letters. Example:
const int PI = 3.14;
It's generally good to avoid lower case letter `L', or the letter
`O' in names unless they are part of normal words. This is to avoid
confusion with the numbers 1 and 0. For example, is "cell" c- e -
1- ONE or c- e- 1-1?
Avoid names that differ only in case, look similar, or differ only slightly. For example, InputData, InData and DataInput will certainly be confusing if used in the same program.
Names of functions should reflect what they do (printArray), or what they return (getAge). Boolean variable names should sound like Yes/No things — "isEmpty" and "isFinished" are possible examples.
Miscellaneous but Important Stuff
No line of code should wrap beyond the right margin. If a line of
code becomes too long, break it up into pieces. Remember the
compiler largely ignores extra whitespace in your programs (but be
careful with strings).
Always use the most appropriate operator or construct for the work
you want it to do. Good design and clarity take precedence over
optimization. Do not declare or use more variables than are
necessary.
Numerical constants ("magic numbers") must not be coded
directly. The only allowable exceptions are for 0, 1 or -1, and
those which are not likely to change; for example code determining
if a number is even can use the number 2 since it is not likely to
change. Numerical constants must have a comment explaining the
value if it is not evident from the name.
Know what you don't know and then know it
Some students feel they know, though they actually don't know. In this
case, they cannot clear their misunderstandings, and it's a big problem.
How can you fix your misunderstandings if you think you don't have any?
A bigger problem is that misunderstandings will pile up as the time goes
by. For example, a troubling student may take the following unfortunate
path:
| Week 1
| I understand everything! Well, homework is a bit difficult, and my
code doesn't work. Doesn't matter! I can just copy and paste the sample
code and change some parts here and there; done!
|
He should have identified which part of his code was wrong and cleared his
misunderstanding through debugging it, instead of just copying and pasting
the sample code.
|
| Week 2
| It's still OK. The instructor told us something that didn't make
sense, but in general I understand the concepts. Hmm... homework and lab
this week are hard.
| His misunderstandings have piled up to some degree, but
unfortunately, he doesn't know what he have missed. Just something is
unclear to him.
|
| Week 3
| This is a hard class, but it's still interesting. I can't finish one
homework but it's fine.
| It's not fine; he has a problem. He really needs to see his
instructor.
|
| ...
|
| Week 6
| Cruel instructor, I know how to program, but the practicum is too
hard for me even to touch!. Bad instructor, EI is useless.
|
Practicum was fair to most students. EI was painful to both him and the
instructor. The student has so many misunderstandings, but he doesn't know
what they are, and the instructor had to probe and identify his
misunderstandings.
|
Practical tips
Here are a few practical tips that will help you identify what you know
and don't know.
- The more independent a programmer is, the better. Of course, you need
to look at lecture notes, sample programs, and other materials to write
your program.
However, do this before writing the code, but try to avoid
looking at them if possible while writing your
code. In particular, if you are really new to programming, try to
write your code from scratch without doing any copy-and-paste, at
least for the first three weeks. I know it's impossible to do so; try with
your discretion.
There are some benefits to this approach:
- You will become more conscious which concepts (or less important
details) you miss. This way, you can identify your misunderstandings
and fix them with more ease.
- You will write a code faster. Access to something in your brain is
much faster than in any other storage. Memory
hierarchy matters.
- Your brain seems to do creative
synthesis. You may gain more fundamental perspectives on
programming if you put more in your brain. However, things outside your
brain always stay the same to you.
- The devil is in the details. Don't forget that is it you as a
programmer who are responsible for all the bits and pieces of your
program. Things may seem simple at a first look, but usually they will
take more time and effort to complete than expected.
As one more example, the online notes sometimes explain technical details.
In this case, reading one paragraph may take even 5 minutes or more to
work out all the details in your brain. Don't skip through the details.
The devil is in the details.
- Step back, and think again.
When you finish a task, take a brief moment and step back. Check if you
get both the big picture logic and the small details to implement the
logic. See if there are some inconsistencies and fix them if any.
- How valuable is a car that doesn't run? It's useless, and I
won't buy the car. Likewise, however many lines your source code may
have, if it doesn't work, it's useless, and I won't buy your program. Try
to make a good, working product. If your code doesn't work, you are
missing something; what is it?
Know your speed and manage your time
accordingly
At the end of the 2nd week, you must know how long it take you to
finish the following on average:
- Reading one day's lecture notes.
- Finishing one assignment of homework.
- Finishing a lab.
Then, you need to allocate enough of your time in your schedule in order
to be successful in this course.
There are three projects in this course. As a rule of thumb, you will need
3-6x of lab time for finishing a project.