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 ﬁles
src Project source ﬁles and private headers
test (or tests) Source ﬁles for testing the project
Empty directories
bin Output executables
build All intermediate ﬁles
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 ﬁles 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 Conﬁguration ﬁle 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++ ﬁle 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 ﬁle
• source/implementation .c .cc .cpp .cxx
Common conventions:
• .h .c .cc Google
• .hh .cc
• .hpp .cpp
• .hxx .cxx
9/85
Common Rules
The ﬁle 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 ﬁles, private headers, header implementations in src/ directory
• The main ﬁle (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 ﬁlename and include .test suﬃx,
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 ﬁles (or module interface and implementation ﬁles) are next
to each other (no include/ and src/ split)
• Headers are included with <> and contain the project directory preﬁx, for
example, <hello/hello.hpp> (no need of "" syntax)
• Header and source ﬁle extensions are .hpp / .cpp ( .mpp for module
interfaces). No special characters other than
and - in ﬁle names with . only
used for extensions
• A source ﬁle that implements a module’s unit tests should be placed next to that
module’s ﬁles 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, ineﬃciency, 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 ﬁles
- 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 deﬁning macros, especially in headers Google
- Do not use macro for enumerators, constants, and functions
WebKit, Google
※ Use a preﬁx for all macros related to the project MYPROJECT MACRO
Google, Unreal
※ #undef macros wherever possible Google
- Even in the source ﬁles if unity build is used (merging multiple source ﬁles 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 ﬁrst #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 speciﬁcation 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 ﬁles:
Items local to a source ﬁle (e.g. .cpp) ﬁle should be wrapped in an anonymous
namespace. While some such items are already ﬁle-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 ﬁxed-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 oﬀsets,
vector indices, and so on. (integer overﬂow behavior for signed types is undeﬁned)
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 ﬂoating point == , < , etc. Hic
※ Use signed types for arithmetic Core
Style:
• Use ﬂoating-point literals to highlight ﬂoating-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 modiﬁed 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 ﬁt 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 deﬁnition Clang-Tidy
• Do not use inline when declaring a function (only in the deﬁnition) LLVM
• Do not separate declaration and deﬁnition 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 deﬁne implicit conversions. Use the explicit keyword for conversion
operators and constructors Google, Core
∗ Prefer = default constructors over user-deﬁned / 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 ﬁrst character is helpful in ﬁltering 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 ﬂow (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 deﬁne 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 eﬀective
※ 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 diﬀerence 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 ﬁnd 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 diﬀerent things. Use a speciﬁc 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 ﬁne 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 eﬀect 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 preﬁx for modiﬁer 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 ﬁrst word letter (sometimes called Pascal style or uppercase
Camel style) (less readable, shorter names)
CapitalStyle
Camel-Back style Uppercase ﬁrst word letter except the ﬁrst 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 preﬁx,
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 conﬂicts 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 conﬁguration ﬁle
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 ﬁle
• 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 diﬀerent
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 ﬁles Mozilla, Chromium
∗ Do not use UTF characters* for portability, prefer ASCII
∗ If UTF is needed, prefer UTF-8 encoding for portability Chromium
• Declare each identiﬁer 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 ﬁles with a blank line Mozilla, Unreal
* Trojan Source attack for introducing invisible vulnerabilities
82/85
Code
Documentation
Code Documentation 1/3
∗ Any ﬁle start with a license LLVM, Unreal
∗ Each ﬁle should include
- @author name, surname, aﬃliation, email
- @date e.g. year and month
- @file the purpose of the ﬁle
in both header and source ﬁles
• Document each entity (functions, classes, namespaces, deﬁnitions, etc.) and only
in the declarations, e.g. header ﬁles
83/85
Code Documentation 2/3
• The ﬁrst 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