C++ Style Guide
Programming style is one of
the holy wars of
computer programming. However, regardless of your tastes one thing is
certain: when in Rome, do as the Romans do. That is,
learning the accepted style of a programming language is just as important as
learning the language itself.
It seems that every company or group has its own style guidelines (e.g.,
the linux
kernel C guide,
the Google
C++ style guide, or
the Mozilla
coding style guide). Regardless, for consistency's sake, we'll stick to a
set of common rules for our code. You won't lose points for a few small style
violations; it's only if your files flagrantly violate style that you will
lose points.
(This guide borrows heavily from the OCaml style guide for old iterations of CIS 500.)
Indentation and Spacing
- 80 Column Limit: No line of code can have more
than 80 columns. Using more than 80 columns causes your code to wrap around to
the next line which is devastating to the readability of your code.
- No Tab Characters: Do not use the tab character
(0x09). Instead, use spaces to control indenting. Ensure that your editor of
choice uses spaces when you insert a tab (i.e., soft tabs).
- Indent Two or Four Spaces: Most lines that indent
code should only indent by two or four spaces more than the previous line of
code. Pick one and be consistent.
- Line Breaks: Obviously the best way to stay
within the 80 character limit imposed by the rule above is pressing the enter
key every once and a while. Including empty lines should only be done between
declarations (e.g., class definitions or field/method definitions within
classes) and should be restricted to a single empty line at most.
If a declaration or expression extends over 80 characters, indent to the
opening delimeter of the declaration or expression. For example
bool LargeMethod(FirstVeryLargeParamterType t1,
SecondVeryLargeParameterType t2,
ShortThirdParameterType t3)
{
return (SomeBooleanFunction(t1, t2) ||
AnotherBooleanFunction(t2, t3) ||
SomeBooleanFunction(t1, t3));
}
uses line breaks and indention to break up long parameter lists and boolean expressions.
- Use K&R or Allman style braces: K&R looks like this:
namespace N {
class C {
void f() {
int x;
}
};
}
Allman style braces push the opening brace onto its own line:
namespace N
{
class C
{
void f()
{
int x;
}
};
}
Pick a style of braces and consistently use that style on any given
homework or the project.
Comments
- Comments go above the code they reference: For
the sake of consistency (and to avoid issues with the 80 column limit), place
comments above code. (If the comment is super-short, you can get away with
placing it off to the side, but don't do it too often.) For example,
/* This is a well-placed comment. */
#define AN_IMPORTANT_NUMBER 42
// So is this.
#define A_SOMEWHAT_IMPORTANT_NUMBER 42
versus other places, e.g.,
#define AN_IMPORTANT_NUMBER 42 // This is a long comment off to the side
/* ...or a comment below. */
- Avoid Useless Comments: Comments that merely
repeat the code it references or state the obvious are a travesty to
programmers. Comments should state the invariants, the non-obvious, or any
references that have more information about the code.
- Avoid Over-commenting: Incredibly long comments
are not very useful. Long comments should only appear at the top of a file ---
here you should explain the overall design of the code and reference any
sources that have more information about the algorithms or data structures.
All other comments in the file should be as short as possible. After all,
brevity is the soul of wit. Most often the best place for any comment is just
before a function declaration. You should only need to comment inside the body
of a function if it is extremely long or complicated --- variable naming
should normally be enough.
Naming
- Use meaningful names: Variable names should
describe what they are for. Distinguishing what a variable references is best
done by following a particular naming convention (see suggestion below).
Variable names should be words or combinations of words except in special
cases where single letter variables are understood,
e.g., i and j for loop variables.
- Case and naming conventions: The following
table outlines the capitalization conventions we will use for names (in C++):
Identifier |
Case |
Example |
Class |
Pascal |
AppDomain |
Method |
Pascal |
ToString |
Parameters, Locals, and Fields |
Lower-case-underscores |
my_variable |
Namespace |
Lower-case-underscores |
std::my_namespace |
Enumeration type |
Pascal |
ErrorLevel |
Enumeration values |
Angry |
FATAL_ERROR |
Macros |
Angry |
MY_AWESOME_MACRO |
Definitions: Pascal case capitalizes the first letter of each word in the
name. Lower-case-underscores (LCU) has no capital letters and separates words
by underscores. Angry case is all-caps with words separate by
underscores.
- Don't abuse typedef and using
namespace in header files: Only typedef types that would
be useful to someone who #includes the header file, because whatever
you typedef in a header file carries over to any file that includes
it. When it comes to using namespace, you usually
shouldn't put this line in the header file for the same reason --- it
automatically carries over to any file that #includes it, and could cause some
name clashes.
Verbosity
- Don't rewrite existing code: The C and C++ standard
libraries have a number of functions and data structures --- use them
(unless otherwise stated)!
- Boolean Zen: Remember that the type of the
condition in an if-statement is bool. Avoid redundancy in your condition if
you already have a value of type bool. For example
if (foo == true) { /* ... */ }
is redundant as foo must be a boolean variable. Therefore, we should rewrite this as
if (foo) { /* ... */ }