C/C++ Style Guide for SSU
Introduction
The style guidelines identified in this document represent the default standards for C/C++ programs that are written for courses within the Department of Computer Science at Sonoma State University.
Purpose
Computer programs convey proposed solutions to problems and have at least three audiences:
- The original programmer, or the programmer's team, who are developing, debugging, or refining a solution.
- Other programmers who may wish to understand, review, modify, or expand a program.
- The compiler which will translate the program to machine language for subsequent machine execution.
As a vital mechanism for effective communication, programs must convey solutions clearly and concisely, and programs must be easily readable by a broad audience: a programmer, the programmer's team, and future programmers who may need to study, correct, or maintain the code. Google identifies further "Background" and "Goals of the Style Sheet" at the beginning of Google's C++ Style Guide.
Although the C/C++ Programming Language allows programmers to utilize a wide range of formatting conventions, the programming culture for both C/C++ and Java largely has settled upon several widely-adopted conventions. Although some style elements vary somewhat from one organization to another, several central elements are identified and will form the style manual for use within computer science courses at Sonoma State University (unless otherwise stated by the instructor of a specific course).
Alignment with Doxygen
Doxygen allows the automatic generation of html and Latex documentation directly from the annotations in C/C++ programs. Many elements in this style guide are compatible with and conformant to Doxygen's code annotations.
Individual faculty may or may not require programs to conform to all of Doxygen's conventions. If faculty require code submissions to be fully conformant with Doxygen annotations, they may require source code and/or documentation files to be submitted as artifacts.
Doxygen relies upon the software package graphviz for generating images for calling diagrams, class diagrams, and file dependencies. See the Tutorial: Using Doxygen with graphviz for resources.
Doxygen
Doxygen is the de facto standard tool for generating documentation from annotated C++ sources, but it also supports other popular programming languages such as C, Objective-C, C#, PHP, Java, Python, IDL (Corba, Microsoft, and UNO/OpenOffice flavors), Fortran, VHDL and to some extent D.
Example configuration files to create Doxygen-generated documentation are included for every sample project with this style guide. If you like, you can checkout the repository and re-build its documentation to experiment.
Sample Project | Using Doxygen | Using Doxygen + dot |
---|---|---|
directory/ |
HTML PDF | HTML PDF |
fibonacci/ |
HTML PDF | HTML PDF |
sort-comparisons/ |
HTML PDF | HTML PDF |
Whitespace
These conventions are intended for any code that will be read on a screen or printed on paper.
Line Length
Ensure that no line of code is longer than 80 characters.
Info
The 80 character rule is a common line limit in C/C++ style guides. While technological constraints originating the rule (punchcard length and dumb terminal width) may no longer be relevant, this standard re-affirms its reasonableness as a limit.
Use spaces for indentation
Any block of code enclosed in curly braces should be indented one level deeper than the surrounding code.
- Choose a reasonable and consistent convention for indentation; generally 3--5 spaces is acceptable. We recommend 3 spaces for indentation.
- Although a programmer may choose indenting between 3 and 5 characters within a block, all indenting must be consistent throughout the code. Thus, if indentation within an
if
block is 4 spaces in one instance, then all blocks (if
,while
, functions, etc) should also be indented 4 spaces. - Do not indent with tab characters (
\t
). Tab stop settings vary from one environment to another.
Tip: Adjust the tab settings of your editor
Set the "Tab policy" of your editor for all projects.
- For Eclipse: see "Spaces only" option".
- For emacs: see Google's C/C++ style for c-mode.
Use curly braces consistently
Use "Egyptian"-style curly braces in your code in accordance with the C/C++ style guidelines.
Example
Use curly braces around all blocks
Although C/C++ permits the omission of curly braces in cases where the body if-statement or loop consists of a single statement, we require that every block (no matter the number of statements) be enclosed inside curly braces on a new line.
It is far too easy to make programming errors of this form otherwise:
One statement per line
There should be no more than one statement (declaration, assignment, or function call) on any line of your program.
Vertical whitespace to separate chunks of code
Within a block of code, use vertical whitespace (blank lines) to separate groups of statements. This makes code more readable and clarifies which statements are logically related. Note that if you have to resort to this rule, you should consider breaking your code up into multiple functions instead.
Use spaces around operators
Every C/C++ operator should have spaces around it (except the dot operator, e.g. method calls c.foo()
). Use parentheses to communicate precedence. For example, 5 - (x + 4) * 8
Printing standards
These additional requirements are only relevant when printing code on paper.
-
Use only full sheets of clean white paper. Colored paper or paper with other printing on one or both sides is not appropriate.
-
Use a fixed-width font of size at least 12 point size. We recommend Courier font.
-
Use a dark font (e.g., black, dark blue, dark green, dark brown) on a light background (e.g., white or cream). Dark backgrounds are wasteful of ink resources, expensive to print, and sometimes streak or bleed together when printed. Thus, dark backgrounds are unacceptable.
Naming Conventions
Use descriptive names
Names should reflect their use within the context of the program. For example, total
and subTotal
describe the contents of the variables, while foo
and bar
do not.
Use more descriptive names for larger scopes
Variables that have greater scope should have more descriptive names. While it is often preferred to use a short name like i
or j
as a loop index, when the scope of an identifier increases, so should the meaningfulness of its name. For example, prefer leftChild
over l
for a class field.
Naming variables and methods
All single-word names should be in lowercase.
For multiple word names:
- In C/C++, use lowerCamelCase for variable and method names, where subsequent words should be joined with their first character capitalized and should not contain underscores.
- In C, it is acceptable to use snake_case for variable and method names (subsequent words are joined with underscores, in lower case). Do not mix snake_case and lowerCamelCase conventions.
Naming classes
Use UpperCamelCase for class names and enum type names. Do not capitalize acronyms within camelCased names; the string "TCP socket ID" should be written TcpSocketId
rather than TCPSocketID
.
Naming constant and enum values
Values that are constants, including final static variables and enum values, should follow CAPITALIZED_WITH_UNDERSCORES
conventions, in which all-caps words are separated by underscore characters.
Naming files
Follow common conventions for file extensions. In particular, use .h
for header files, .c
for C code, .cpp
for C++ code, and .tcc
for C++ template files.
Although the C Standard does not require specific file extensions and #include
statements require explicit inclusion of extensions within file names, numerous editors and some compilers (e.g., gcc
) draw inferences from the extensions used.
Comments
Do not over-comment code
If a piece of code is reasonably obvious to experienced C/C++ programmers, then it does not need to be commented. Be judicious; if you are unsure, it is often best not to include a redundant comment. If you feel like it is necessary to extensively comment your code, consider how to rewrite it to make it more straightforward.
Comments describe purpose over implementation
The code itself is a description of an implementation, so it is unnecessary to comment what the code is doing (e.g., x++
does not need a comment like "Increment x"). Instead, describe at a high level the intended use of the piece of code, such as what task the function performs.
Include a program header
At the start of a program file, write comments to introduce the program. These should include:
- a description of the overall purpose of the program, such as the problem the program addresses.
- a listing of the programmers involved, with an
@author
annotation for each author. - a list of all references from which the code (or ideas for the code) were drawn, with a
@remark
annotation. - each reference should be in its own
@remark
block:
Example
/**
* @remark Uses a basic recursive approach to compute the
* n-th Catalan number, both with and without dynamic prog.
*
* @author Henry M. Walker
* @author Ali K. Kooshesh
*
* @remark References
*
* @remark Dynamic Programming: Anany Levitin, "The Design and
* and Analysis of Algorithms", Second Edition,
* Chapter 8: Dynamic Programming
*
* @remark Dynamic Programming: Anany Levitin, "The Design and
* and Analysis of Algorithms", Second Edition,
* Section 2.5: Example: Computing the nth Fibonacci Number
*
* @remark People involved in problem/program discussions:
* - Mark Gondree
*/
Tip
Doxygen also supports using bibliographic references in BibTex format (.bib
files). BibTex/LaTeX details are beyond the scope of this Style Guide.
Procedures should be commented
All C functions, all C++ public methods, and all non-trivial C++ private methods should include comments holding documentation. Each should describe:
- the function's intended use,
- the function's parameters, using a
@param
tag for each function/method parameter, - the function's return value, using a
@returns
tag (if applicable), - exceptions thrown (if any), and
- any pre-conditions using a
@pre
tag.
Example
Logic within procedures should be commented
Within a procedure or method, include comments to explain the logic of each section of code. At a minimum, at least one comment describing logic should be included within any block of 20 lines.
Control blocks should be commented
Every non-trivial control block (if
, for
, while
, etc) should include a “why” comment: why is this block of code needed? What is the purpose of the condition in the case of a controlled block of code.
Example
No dead code
Remove any dead or commented-out code from your source files before submission. Commenting out code is useful in development, but do not submit commented-out code in your final product.
Reuse code and efficiency
Use library functions, when possible
C/C++ has quite a rich standard library. You should make use of its provided functions instead of re-implementing them (unless otherwise directed). Your re-implementation will almost always be less efficient (and is less likely to be correct).
Avoid redundant computation
Use a helper variable or method to avoid computing values multiple times. If you find that a particular sequence of computations is being repeated more than twice, you should assign it to a variable and/or abstract it into a helper function which returns the desired value.
Avoid redundant or verbose expressions
Write expressions for if
conditions, while
loop guards, etc. in the most succinct and expressive way possible. Especially, consider whether a long expression involving multiple ||
or &&
operators is easily readable and whether it could be written with fewer or simpler sub-expressions.
Organization
Class implementation organization
Classes should be organized internally in the order:
- Import statements,
- Fields,
- Constructors, and
- Methods
Decompose logic into unique, specific tasks
Methods and classes should perform one specific and unique task. This is known as the principle of separation of concerns: each class and method should be responsible for one thing and one thing only. Your program should be composed of a group of such classes which cooperate to achieve a goal.
Put another way: avoid creating a single method or class that "does too much," meaning a method or class that serves multiple disjoint purposes or is responsible for too much. Such implementations are often unwieldy and difficult to extend or debug.
Class extension should always represent "is-a" relationships
When creating a subclass, make sure that the subtype Foo "is-a" version or variant of supertype Bar.
Tip
If the relationship is more appropriately described by a "has-a" relationship, then consider making Bar a field of Foo instead.
More Examples, with Annotations
Example: header
/**
designates the beginning of an annotation for use in Doxygen. Whitespace is needed after the second asterisk. If a line of astericks is desired at the start of a comment block, leave 1 space after the second asterisk before completing the line. Doxygen does not copy entire lines of asterisks (e.g., at the beginning or end of an annotation.) However, Doxygen does include individual asterisks within a line of text.- The initial
@remark
tag identifies the purpose of program - The
@remark
tag tells Doxygen that a comment follows.- The comment continues until a blank line or the next tag
- If two or more
@remark
tags, commentary for each tag starts on a new line.
- The author, file, and date tags tell Doxygen to use specified labels and formatting
- Comment for
time.h
indicates the function motivating including this library
Example: function
- The block for a function can combine two forms: use a rectangle of asterisks, in the style of a text box; leave a space after the second asterisk of the opening line, as required by Doxygen.
- This function header identifies purpose of function, clarification of parameter
n
with a@param
tag, clarification of pre-condition forn
with a@pre
tag, identification of value returned with a@returns
tag - Although the
if
andelse
control only one statement, braces are still used for consistency and to ease the addition of additional statements later.
Example: main()
- Initial comment identifies primary scope of the main procedure
- Comment for reps briefly describes purpose of variable
- Text within printf clarifies purpose of output -- no need to say more
- Comments identify a section of code which handles timing
- This section section of code is separated by white space and a comment, to highlight the two different blocks of logic handling timing
Acknowledgments
Although the C/C++ Programming Language allows programmers to utilize a wide range of formatting conventions, C/C++ and Java programming cultures largely have settled upon several widely-adopted conventions. Although some style elements vary somewhat from one organization to another, elements in this style guide are derived from these primary sources:
- Google C++ Style Guide, (accessed April 29, 2022)
- Google Java Style Guide
- Code Conventions for the Java Programming Language (from Oracle, Revised April 20, 1999)
- CIS 120 at the University of Pennsylvania.
- CSC 207 Java Style Guide by Peter-Michael Osera, Grinnell College.