Modern C++
Programming
13. Code Conventions
Federico Busato
2024-03-29
Table of Contents
1 C++ Project Organization
Project Directories
Project Files
“Common” Project Organization Notes
Alternative - “Canonical” Project Organization
2 Coding Styles and Conventions
Coding Styles
3 #include
1/85
Table of Contents
4 Macro and Preprocessing
5 namespace
6 Variables and Arithmetic Types
7 Functions
8 Structs and Classes
2/85
Table of Contents
9 Control Flow
10 Modern C++ Features
11 Maintainability
12 Naming
13 Readability and Formatting
14 Code Documentation
3/85
C++ Project
Organization
“Common” Project Organization
4/85
Project Directories 1/2
Fundamental directories
include Project public header files
src Project source files and private headers
test (or tests) Source files for testing the project
Empty directories
bin Output executables
build All intermediate files
doc (or docs) Project documentation
5/85
Project Directories 2/2
Optional directories
submodules Project submodules
third party (less often deps/external/extern) dependencies or external
libraries
data (or extras) Files used by the executables or for testing
examples Source files for showing project features
utils (or tools, or script) Scripts and utilities related to the project
cmake CMake submodules (.cmake)
6/85
Project Files
LICENSE Describes how this project can be used and distributed
README.md General information about the project in Markdown format *
CMakeLists.txt Describes how to compile the project
Doxyfile Configuration file used by doxygen to generate the documentation (see
next lecture)
others .gitignore, .clang-format, .clang-tidy, etc.
* Markdown is a language with a syntax corresponding to a subset of HTML tags
github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet
7/85
Readme and License
README.md
README template:
- Embedded Artistry README Template
- Your Project is Great, So Let’s Make Your README Great Too
LICENSE
Choose an open source license:
choosealicense.com
License guidelines:
Why your academic code needs a software license
8/85
File extensions
Common C++ file extensions:
header .h .hh .hpp .hxx
header implementation .i.h .i.hpp -inl.h .inl.hpp
(1) separate implementation from interface for inline functions and templates
(2) keep implementation “inline” in the header file
source/implementation .c .cc .cpp .cxx
Common conventions:
.h .c .cc Google
.hh .cc
.hpp .cpp
.hxx .cxx
9/85
Common Rules
The file should have the same name of the class/namespace that they
implement
class MyClass
my class.hpp (MyClass.hpp)
my class.i.hpp (MyClass.i.hpp)
my class.cpp (MyClass.cpp)
namespace my np
my np.hpp (MyNP.hpp)
my np.i.hpp (MyNP.i.hpp)
my np.cpp (MyNP.cpp)
10/85
“Common” Project Organization Notes
Public header(s) in include/
source files, private headers, header implementations in src/ directory
The main file (if present) can be placed in src/ and called main.cpp
Code tests, unit and functional (see C++ Ecosystem I slides), can be
placed in test/ , or unit tests can appear in the same directory of the
component under test with the same filename and include .test suffix,
e.g. my file.test.cpp
11/85
“Common” Project Organization Example
<project name>
include/
public header.hpp
src/
private header.hpp
templ class.hpp
templ class.i.hpp
(template/inline functions)
templ class.cpp
(specialization)
subdir/
my file.cpp
README.md
CMakeLists.txt
Doxyfile
LICENSE
build/ (empty)
bin/ (empty)
doc/ (empty)
test/
my test.hpp
my test.cpp
...
12/85
“Common” Project Organization - Improvements
The “common” project organization can be
improved by adding the name of the project
as subdirectory of include/ and src/
This is particularly useful when the project
is used as submodule (part of a larger
project) or imported as an external library
The includes now look like:
# include <my_project/public_header.hpp>
<project name>
include/
<project name>/
public header.hpp
src/
<project name>/
private file.hpp
13/85
Alternative - “Canonical” Project Organization 1/2
Header and source files (or module interface and implementation files) are next
to each other (no include/ and src/ split)
Headers are included with <> and contain the project directory prefix, for
example, <hello/hello.hpp> (no need of "" syntax)
Header and source file extensions are .hpp / .cpp ( .mpp for module
interfaces). No special characters other than
and - in file names with . only
used for extensions
A source file that implements a module’s unit tests should be placed next to that
module’s files and be called with the module’s name plus the .test second-level
extension
A project’s functional/integration tests should go into the tests/ subdirectory
14/85
Alternative - “Canonical” Project Organization 2/2
<project name> (v1)
<project name>/
public header.hpp
private header.hpp
my file.cpp
my file.mpp
my file.test.cpp
tests/
my functional test.cpp
build/
doc/
...
<project name> (v2)
<project name>/
public header.hpp
private/
private header.hpp
my internal file.cpp
my internal file.test.cpp
tests/
my functional test.cpp
build/
doc/
...
15/85
References
Kick-start your C++! A template for modern C++ projects
The Pitchfork Layout
Canonical Project Structure
16/85
Coding Styles and
Conventions
Overview
“One thing people should remember is
there is what you can do in a language and
what you should do”
Bjarne Stroustrup
17/85
Overview
Most important rule:
BE CONSISTENT!!
“The best code explains itself
Google
18/85
Overview
“80% of the lifetime cost of a piece of
software goes to maintenance”
Unreal Engine
19/85
Code Quality
“The worst thing that can happen to a code base is size”
Steve Yegge
20/85
Bad Code
How my code looks like for other people?
abstrusegoose.com/432
21/85
Coding Styles 1/3
Coding styles are common guidelines to improve the readability, maintainability,
prevent common errors, and make the code more uniform
LLVM Coding Standards. llvm.org/docs/CodingStandards.html
Google C++ Style Guide. google.github.io/styleguide/cppguide.html
Webkit Coding Style. webkit.org/code-style-guidelines
Mozilla Coding Style. firefox-source-docs.mozilla.org
Chromium Coding Style. chromium.googlesource.com,
c++-dos-and-donts.md
22/85
Coding Styles 2/3
Unreal Engine - Coding Standard
docs.unrealengine.com/en-us/Programming
µOS++
micro-os-plus.github.io/develop/coding-style
micro-os-plus.github.io/develop/naming-conventions
More educational-oriented guidelines
C++ Guidelines
isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines
23/85
Coding Styles 3/3
Secure Coding
High Integrity C++ Coding Standard. www.perforce.com/resources
CERT C++ Secure Coding. wiki.sei.cmu.edu
Critical system coding standards
Misra - Coding Standard. www.misra.org.uk
Autosar - Coding Standard. www.misra.org.uk
Joint Strike Fighter Air Vehicle.
www.perforce.com/blog/qac/jsf-coding-standard-cpp
24/85
Legend
Important!
Highlight potential code issues such as bugs, inefficiency, and can compromise
readability. Should not be ignored
Useful
It is not fundamental, but it emphasizes good practices and can help to prevent
bugs. Should be followed if possible
Minor / Obvious
Style choice or not very common issue
25/85
#include
#include 1/5
Every include must be self-contained
- include every header you need directly
- do not rely on recursive #include
- the project must compile with any include order
LLVM, Google, Unreal, µOS++, Core
Include as less as possible, especially in header files
- do not include unneeded headers
- minimize dependencies
- minimize code in headers (e.g. use forward declarations)
LLVM, Google, Chromium, Unreal, Hic, µOS++
26/85
#include 2/5
Order of #include LLVM, WebKit, Core
(1) Main module/interface header, if exists (it is only one)
space
(2) Local project includes (in lexicographic order)
space
(3) System includes (in lexicographic order)
Note: (2) and (3) can be swapped Google
System includes are self-contained, local includes might not
27/85
#include 3/5
Project includes LLVM, Google, WebKit, Hic, Core
Use "" syntax
Should be absolute paths from the project include root
e.g. #include "directory1/header.hpp"
System includes LLVM, Google, WebKit, Hic
Use <> syntax
e.g. #include <iostream>
28/85
#include 4/5
Always use an include guard
macro include guard vs. #pragma once
- Use macro include guard if portability is a very strong requirement
LLVM, Google, Chromium, Core
- #pragma once otherwise WebKit, Unreal
#include preprocessor should be placed immediately after the header comment
and include guard LLVM
Forward declarations vs. #includes
Prefer forward declaration: reduce compile time, less dependency Chromium
Prefer #include : safer Google
29/85
#include 5/5
Use C++ headers instead of C headers:
<cassert> instead of <assert.h>
<cmath> instead of <math.h>, etc.
Report at least one function used for each include
<iostream> // std::cout, std::cin
# include "my_class.hpp" // MyClass
[ blank line ]
# include "my_dir/my_headerA.hpp" // npA::ClassA, npB::f2()
# include "my_dir/my_headerB.hpp" // np::g()
[ blank line ]
# include <cmath> // std::fabs()
# include <iostream> // std::cout
# include <vector> // std::vector
30/85
Macro and
Preprocessing
Macro and Preprocessing 1/4
Avoid defining macros, especially in headers Google
- Do not use macro for enumerators, constants, and functions
WebKit, Google
Use a prefix for all macros related to the project MYPROJECT MACRO
Google, Unreal
#undef macros wherever possible Google
- Even in the source files if unity build is used (merging multiple source files to
improve compile time)
31/85
Macro and Preprocessing 2/4
Always use curly brackets for multi-line macro
# define MACRO \
{ \
line1; \
line2; \
}
Always put macros after #include statements Hic
Put macros outside namespaces as they don’t have a scope
32/85
Macro and Preprocessing - Style 3/4
Close #endif with the respective condition of the first #if
# if defined(MACRO)
...
# endif // defined(MACRO)
The hash mark that starts a preprocessor directive should always be at the
beginning of the line Google
# if defined(MACRO)
# define MACRO2
# endif
33/85
Macro and Preprocessing - Style 4/4
Place the \ rightmost for multi-line macro
# define MACRO2 \
macro_def...
Prefer #if defined(MACRO) instead of #ifdef MACRO
Improve readability, help grep-like utils, and it is uniform with multiple conditions
# if defined(MACRO1) && defined(MACRO2)
34/85
namespace
Namespace 1/3
Avoid using namespace -directives at global scope
LLVM, Google, WebKit, Unreal, Hic, µOS++
Limit using namespace -directives at local scope and prefer explicit
namespace specification Google, WebKit, Unreal
Always place code in a namespace to avoid global namespace pollution
Google, WebKit
35/85
Namespace- Anonymous 2/3
Avoid anonymous namespaces in headers Google, Cert
anonymous namespace vs. static
- Prefer anonymous namespaces instead of static variables/functions
Google, Core
- Use anonymous namespaces only for inline class declaration, static otherwise
LLVM, static
Anonymous namespaces and source files:
Items local to a source file (e.g. .cpp) file should be wrapped in an anonymous
namespace. While some such items are already file-scope by default in C++, not all are;
also, shared objects on Linux builds export all symbols, so anonymous namespaces (which
restrict these symbols to the compilation unit) improve function call cost and reduce the
size of entry point tables Chromium, Core, Hic
36/85
Namespace - Style 3/3
The content of namespaces is not indented LLVM, Google, WebKit
namespace ns {
void f() {}
}
Close namespace declarations LLVM, Google
} // namespace <namespace_identifier>
} // namespace (for anonymous namespaces)
37/85
Variables and
Arithmetic Types
Variable 1/3
Place a variable in the narrowest scope possible, and always initialize
variables in the declaration
Google, Isocpp, Mozilla, Hic, muOS, Cert
Avoid static (non-const) global variables LLVM, Google, Core, Hic
Use assignment syntax = when performing “simple” initialization Chromium
38/85
Arithmetic Types 2/3
Use fixed-width integer type (e.g. int64 t , int8 t , etc.)
Exception: int Google, int/unsigned Unreal
size t vs. int64 t
- Use size t for object and allocation sizes, object counts, array and pointer offsets,
vector indices, and so on. (integer overflow behavior for signed types is undefined)
Chromium
- Use int64 t instead of size t for object counts and loop indices Google
Use brace initialization to convert constant arithmetic types
(narrowing) e.g. int64 t{MyConstant} Google
Use true , false for boolean variables instead numeric values 0, 1 WebKit
39/85
Arithmetic Types 3/3
Do not shift signed operands Hic, Core, µOS
Do not directly compare floating point == , < , etc. Hic
Use signed types for arithmetic Core
Style:
Use floating-point literals to highlight floating-point data types, e.g. 30.0f
WebKit (opposite)
Avoid redundant type, e.g. unsigned int , signed int WebKit
40/85
Functions
Functions 1/3
Limit overloaded functions. Prefer default arguments Google, Core
Split up large functions into logical sub-functions for improving readability and
compile time Unreal, Google, Core
Use inline only for small functions (e.g. < 10 lines) Google, Hic
Never return pointers for new objects. Use std::unique ptr instead
Chromium, Core
int* f() { return new int[10]; } // wrong!!
std::unique_ptr<int> f() { return new int[10]; } // correct
41/85
Functions - Parameters 2/3
Prefer pass by-reference instead by-value except for raw arrays and built-in
types WebKit
Pass function arguments by
const pointer or reference if those arguments
are not intended to be modified by the function Unreal
Do not pass by-const-value for built-in types, especially in the declaration
(same signature of by-value)
Prefer returning values rather than output parameters Google
Do not declare functions with an excessive number of parameters. Use a
wrapper structure instead Hic, Core
42/85
Functions - Style 3/3
Prefer enum to bool on function parameters
All parameters should be aligned if they do not fit in a single line (especially in the
declaration) Google
void f(int a,
const int* b);
Parameter names should be the same for declaration and definition Clang-Tidy
Do not use inline when declaring a function (only in the definition) LLVM
Do not separate declaration and definition for template and inline functions
Google
43/85
Structs and Classes
Structs and Classes 1/3
Use a struct only for passive objects that carry data; everything else is a
class Google
Objects are fully initialized by constructor call Google, WebKit, Core
Prefer in-class initializers to member initializers Core
Initialize member variables in the order of member declaration Core, Hic
Use delegating constructors to represent common actions for all constructors of a
class Core
44/85
Structs and Classes 2/3
Do not define implicit conversions. Use the explicit keyword for conversion
operators and constructors Google, Core
Prefer = default constructors over user-defined / implicit default
constructors Mozilla, Chromium, Core, Hic
Use = delete for mark deleted functions Core, Hic
Mark destructor and move constructor noexcept Core
45/85
Structs and Classes 3/3
Use braced initializer lists for aggregate types A{1, 2} LLVM, Google
Do not use braced initializer lists {} for constructors (at least for containers, e.g.
std::vector ). It can be confused with std::initializer list LLVM
Prefer braced initializer lists {} for constructors to clearly distinguish from
function calls and avoid implicit narrowing conversion
46/85
Inheritance 1/2
Avoid virtual method calls in constructors Google, Core, Cert
Default arguments are allowed only on non-virtual functions
Google, Core, Hic
A class with a virtual function should have a virtual or protected destructor
(e.g. interfaces and abstract classes) Core
Does not use virtual with final/override (implicit)
see A hole in Clang’s -Wsuggest-override
47/85
Inheritance 2/2
Multiple inheritance and virtual inheritance are discouraged
Google, Chromium
Prefer composition to inheritance Google
A polymorphic class should suppress copying Core
48/85
Structs and Classes - Style 1/3
Declare class data members in special way*. Examples:
- Trailing underscore (e.g. member var ) Google, µOS, Chromium
- Leading underscore (e.g. member var ) .NET
- Public members (e.g. m member var ) WebKit
Personal Comment: Prefer member var as I read left-to-right and is less invasive
Class inheritance declarations order:
public , protected , private Google, µOS
First data members, then function members
If possible, avoid this-> keyword
* It helps to keep track of class variables and local function variables
* The first character is helpful in filtering through the list of available variables
49/85
Structs and Classes - Style 2/3
struct A { // passive data structure
int x;
float y;
};
class B {
public:
B();
void public_function();
protected:
int _a; // in general, it is not public in derived classes
void _protected_function(); // "protected_function()" is not wrong
// it may be public in derived classes
private:
int _x;
float _y;
void _private_function();
};
50/85
Structs and Classes - Style 3/3
In the constructor, each member should be indented on a separate line, e.g.
WebKit, Mozilla
A::A(int x1, int y1, int z1) :
x{x1},
y{y1},
z{z1} {
51/85
Control Flow
Control Flow 1/6
Avoid redundant control flow (see next slide)
- Do not use else after a return / break
LLVM, Mozilla, Chromium, WebKit
- Avoid return true/return false pattern
- Merge multiple conditional statements
Prefer switch to multiple if -statement Core
Avoid goto µOS, Core
Avoid
do-while loop Core
Do not use default labels in fully covered switches over enumerations LLVM
52/85
Control Flow - if/else 2/6
if (condition) { // wrong!!
< code1 >
return;
}
else // <-- redundant
< code2 >
//---------------------------
if (condition) { // Corret
< code1 >
return;
}
< code2 >
if (condition) // wrong!!
return true;
else
return false;
//-------------------------
return condition; // Corret
53/85
Control Flow - Loops 3/6
Use early exits ( continue , break , return ) to simplify the code LLVM
for (<condition1>) { // wrong!!
if (<condition2>)
...
}
//-----------------------------
for (<condition1>) { // Correct
if (!<condition2>)
continue;
...
}
Turn predicate loops into predicate functions LLVM
bool var = ...;
for (<loop_condition1>) { // should be an external
if (<condition2>) { // function
var = ...
break;
}
54/85
Control Flow - Comparison 4/6
Tests for null/non-null , and zero/non-zero should all be done with
equality comparisons Core, WebKit
(opposite) Mozilla
if (!ptr) // wrong!!
return;
if (!count) // wrong!!
return;
if (ptr == nullptr) // correct
return;
if (count == 0) // correct
return;
Prefer (ptr == nullptr) and x > 0 over (nullptr == ptr) and 0 < x
Chromium
Do not compare to true/false , e.g. if (x == true)
55/85
Control Flow 5/6
Do not mix signed and unsigned types Hic
Prefer signed integer for loop indices (better 64-bit) Core
Prefer empty() method over size() to check if a container has no items
Mozilla
Ensure that all statements are reachable Hic
Avoid RTTI (dynamic cast) or exceptions if possible
LLVM, Google, Mozilla
56/85
Control Flow - Style 6/6
The if and else keywords belong on separate lines
if (c1) <statement1>; else <statement2> // wrong!!
Google, WebKit
Multi-lines statements and complex conditions require curly braces Google
if (c1 && ... &&
c2 && ...) { // correct
<statement>
}
Curly braces are not required for single-line statements (but allowed)
( for, while, if ) Google, WebKit
if (c1) { // not mandatory
<statement>
}
57/85
Modern C++
Features
Modern C++ Features 1/4
Use modern C++ features wherever possible
static cast reinterpret cast instead of old style cast (type)
Google, µOS, Hic
Do not define implicit conversions. Use the
explicit keyword for conversion
operators and constructors Google, µOS
58/85
Modern C++ Features - C++11/14/17 2/4
Use constexpr instead of macro Google, WebKit
Use using instead typedef
Prefer enum class instead of plain enum Unreal, µOS
static assert compile-time assertion Unreal, Hic
lambda expression Unreal
move semantic Unreal
nullptr instead of 0 or NULL
LLVM, Google, Unreal, WebKit, Mozilla, Hic, µOS
59/85
Modern C++ Features - C++11/14/17 3/4
Use range-based for loops whenever possible
LLVM, WebKit, Unreal, Core
Use auto to avoid type names that are noisy, obvious, or unimportant
auto array = new int[10];
auto var = static cast<int>(var); LLVM, Google
lambdas, iterators, template expressions Unreal (only)
Use [[deprecated]] / [[noreturn]] / [[nodiscard]] to indicate
deprecated functions / that do not return / result should not be discarded
Avoid throw() expression. Use noexcept instead Hic
60/85
Modern C++ Features for Classes 4/4
Always use override/final function member keyword
WebKit, Mozilla, Unreal, Chromium, Hic
Use braced direct-list-initialization or copy-initialization for setting default
data member value. Avoid initialization in constructors if possible Unreal
struct A {
int x = 3; // copy-initialization
int x { 3 }; // direct-list-initialization (best option)
};
Use = default constructors
Use = delete to mark deleted functions
Prefer uniform initialization when it cannot be confused with
std::initializer list Chromium
61/85
Maintainability
Maintainability 1/3
Avoid complicated template programming Google
Write self-documenting code
e.g. (x + y - 1) / y ceil div(x, y) Unreal
Use symbolic names instead of literal values in code Hic
double area1 = 3.14 * radius * radius; // wrong!!
constexpr auto Pi = 3.14; // correct
double area2 = Pi * radius * radius;
62/85
Maintainability 2/3
Do not use reinterpret cast or union for type punning Core, Hic
Enforce const-correctness Unreal
but don’t const all the things
Pass by- const value: almost useless (copy), ABI break
const return: useless (copy)
const data member: disable assignment and copy constructor
const local variables: verbose, rarely effective
Do not overload operators with special semantics && , ˆ Hic
Use assert to document preconditions and assumptions LLVM
Don’t const all the things
63/85
Maintainability 3/3
Address compiler warnings. Compiler warning messages mean something is
wrong Unreal
Ensure ISO C++ compliant code and avoid non-standard extension,
deprecated features, or asm declarations, e.g. register , attribute Hic
Prefer sizeof(variable/value) instead of sizeof(type) Google
Prefer core-language features over library facilities, e.g. uint8 t vs.
std::byte
Prefer core-language features over library facilities
64/85
Naming
Naming
“Beyond basic mathematical aptitude, the difference be-
tween good programmers and great programmers is verbal
ability”
Marissa Mayer
65/85
General Notes on Naming 1/2
Naming is hard. Most of the time, code is shared with other developers. It is
worth spending a few seconds to find the right name
Think about the purpose to choose names
Adopt names commonly used in real contexts (outside the code)
Don’t use the same name for different things. Use a specific name everywhere
Prefer single English word to implementation-focused, e.g.
UpdateConfigFile() save()
Use natural word pair, e.g. create()/destroy() , open()/close() ,
begin()/end() , source()/destination()
66/85
General Notes on Naming 2/2
Don’t overdecorate, e.g. Base/Impl , Factory/Singleton
Don’t list the content, e.g. NameAndAddress ContactInfo
Don’t repeat class/enum names, e.g. Employee::EmployeeName
Avoid temporal attributes, e.g. PreLoad() , PostLoad()
Use adjectives to enrich a name, e.g. Name FullName , Salary
AnnualSalary
Abbreviations are generally bad, longer names are better in most cases (don’t be
lazy)
Naming is Hard: Let’s Do Better, CppCon 2019, Kate Gregory
67/85
Variables Naming 1/2
Use whole words, except in the rare case where an abbreviation would be more
canonical and easier to understand, e.g. tmp WebKit
Avoid short and very long names. Remember that the average word length in
English is 4.8
The length of a variable should be proportional to the size of the scope that
contains it. For example, i is fine within a loop scope
68/85
Variables Naming 2/2
Do not use reserved names Cert
- double underscore followed by any character var
- single underscore followed by uppercase VAR
Use common loop variable names
- i, j, k, l used in order
- it for iterators
69/85
Functions Naming
Should be descriptive verb (as they represent actions) WebKit
Should describe their action or effect instead of how they are
implemented, e.g. partial sort() top n()
Functions that return boolean values should start with boolean verbs, like
is, has, should, does µOS
empty() is empty()
Use set prefix for modifier methods set value() WebKit
Do not use get for observer methods ( const ) without parameters, e.g.
get size() size() WebKit
70/85
Style Conventions
Capital Case Uppercase first word letter (sometimes called Pascal style or uppercase
Camel style) (less readable, shorter names)
CapitalStyle
Camel-Back style Uppercase first word letter except the first one (less readable, shorter
names)
camelBack
Snake style Lower case words separated by single underscore (good readability,
longer names)
snake_style
Macro style Upper case words separated by single underscore (sometimes called
Screaming style) (best readability, longer names)
MACRO_STYLE
71/85
Entity Styles 1/2
Variable Variable names should be nouns
Capital style e.g. MyVar LLVM, Unreal
Snake style e.g. my var Google, Std, µOS
Constant Capital style + k prefix,
e.g. kConstantVar Google, Mozilla
Macro style e.g. CONSTANT VAR WebKit, OpenStack
Enum Capital style + k
e.g. enum MyEnum { kEnumVar1, kEnumVar2 } Google
Capital style
e.g. enum MyEnum { EnumVar1, EnumVar2 } LLVM, WebKit
72/85
Entity Styles 2/2
Namespace Snake style, e.g. my namespace Google, LLVM, Std
Capital style, e.g. MyNamespace WebKit
Typename Should be nouns
Capital style (including classes, structs, enums, typedefs, etc.)
e.g. HelloWorldClass LLVM, Google, WebKit
Snake style µOS (class), Std
Macro Macro style, e.g. MY MACRO Google, Std, LLVM
File Snake style ( my file ) Google
Capital style ( MyFile ), could lead Windows/Linux conflicts LLVM
73/85
Function Styles
Camel-back style, e.g. myFunc() LLVM
Capital style for standard functions
e.g. MyFunc() Google, Mozilla, Unreal
Snake style for cheap functions, e.g. my func() Google, Std
Personal Comment: Macro style needs to be used only for macros to avoid subtle bugs. I adopt
snake style for almost everything as it has the best readability. On the other hand, I don’t want to
confuse typenames and variables, so I use camel style for the former ones. Finally, I also use camel
style for compile-time constants because they are very relevant in my work and I need to quickly
identify them
74/85
Enforcing Naming Styles
Naming style conventions can be also enforced by using tools like
clang-tidy: readability-identifier-naming
.clang-tidy configuration file
Checks: 'readability-identifier-naming'
HeaderFileExtensions: ['', 'h','hh','hpp','hxx']
ImplementationFileExtensions: ['c','cc','cpp','cxx']
CheckOptions:
readability-identifier-naming.ClassCase: 'lower_case'
readability-identifier-naming.MacroDefinitionCase: 'UPPER_CASE'
class MyClass {}; // before
# define my_macro
class my_class {}; // after
# define MY_MACRO
75/85
Readability and
Formatting
Basics
Write all code in English, comments included
Limit line length (width) to be at most 80 characters long (or 100, or 120)
help code view on a terminal LLVM, Google, Mozilla, µOS
Personal Comment: I was tempted several times to use a line length > 80 to reduce the
number of lines, and therefore improve the readability. Many of my colleagues use split-screens or
even the notebook during travels. A line length of 80 columns is a good compromise for everyone
Do not write excessive long file
Is the 80 character limit still relevant in times of widescreen monitors?
Linus Torvalds on 80 column limit
76/85
Spacing 1/2
Use always the same indentation style
- tab 2 spaces Google, Mozilla, Hic, µOS
- tab 4 spaces LLVM, Webkit, Hic, µOS
- (actual) tab = 4 spaces Unreal
Personal Comment: I worked on projects with both two and four-space tabs. I observed less
bugs due to indentation and better readability with four-space tabs. ’Actual tabs’ breaks the line
length convention and can introduce tabs in the middle of the code, producing a very different
formatting from the original one
Separate commands, operators, etc., by a space LLVM, Google, WebKit
if(a*b<10&&c) // wrong!!
if (a * c < 10 && c) // correct
77/85
Spacing 2/2
Prefer consecutive alignment
int var1 = ...
long long int longvar2 = ...
Minimize the number of empty rows
Do not use more than one empty line Google
What is your threshold for a long source file?
78/85
Formatting 1/2
Use always the same style for braces
Same line, aka Kernigham & Ritchie WebKit (func. only), Mozilla
Its own line, aka Allman Unreal, WebKit (function)
Mozilla (class)
int main() {
code
}
int main()
{
code
}
Personal Comment: C++ is a very verbose language. Same line convention helps to keep the
code more compact, improving the readability
79/85
Formatting 2/2
Declaration of pointer/reference variables or arguments may be placed with the
asterisk/ampersand adjacent to either the type or to the variable name for all
symbols in the same way Google
char* c; WebKit, Mozilla, Chromium, Unreal
char *c;
char * c;
The same concept applies to const
const int* West notation
int const* East notation
Personal Comment: I prefer West notation to prevent unintentional cv-qualify (const/volatile) of
a reference or pointer types char &const p , see DCL52-CPP. Never qualify a reference type
with const or volatile
80/85
Reduce Code Verbosity
Use the short name version of built-in types, e.g.
unsigned instead of unsigned int
long long instead of long long int
Don’t const all the things. Avoid Pass by- const , const return, const
data member, const local variables
Use same line braces for functions and structures
Minimize the number of empty rows
Don’t const all the things
81/85
Other Issues
Use the same line ending (e.g. '\n' ) for all files Mozilla, Chromium
Do not use UTF characters* for portability, prefer ASCII
If UTF is needed, prefer UTF-8 encoding for portability Chromium
Declare each identifier on a separate line in a separate declaration Hic, Misra
Never put trailing white space or tabs at the end of a line Google, Mozilla
Only one space between statement and comment WebKit
Close files with a blank line Mozilla, Unreal
* Trojan Source attack for introducing invisible vulnerabilities
82/85
Code
Documentation
Code Documentation 1/3
Any file start with a license LLVM, Unreal
Each file should include
- @author name, surname, affiliation, email
- @date e.g. year and month
- @file the purpose of the file
in both header and source files
Document each entity (functions, classes, namespaces, definitions, etc.) and only
in the declarations, e.g. header files
83/85
Code Documentation 2/3
The first sentence (beginning with @brief ) is used as an abstract
Document the input/output parameters @param[in] , @param[out] ,
@param[in,out] , return value @return , and template parameters @tparam
Document ranges, impossible values, status/return values meaning Unreal
Use always the same style of comment
Use anchors for indicating special issues: TODO , FIXME , BUG , etc.
WebKit, Chromium
84/85
Code Documentation 3/3
Be aware of the comment style, e.g.
- Multiple lines
/**
* comment1
* comment2
*/
- Single line
/// comment
Prefer // comment instead of /* */ allow string-search tools like grep to
identify valid code lines Hic, µOS
µOS++ Doxygen style guide link
Teaching the art of great documentation, by Google
85/85