blob: 4417d065d9dada5edf67e9526e65e3005d059c01 [file] [log] [blame]
Wyatt Heplerf9fb90f2020-09-30 18:59:33 -07001.. _docs-embedded-cpp:
Keir Mierle2c1e56b2019-11-15 16:32:11 -08002
3==================
4Embedded C++ Guide
5==================
6
7This page contains recommendations for using C++ for embedded software. For
8Pigweed code, these should be considered as requirements. For external
9projects, these recommendations can serve as a resource for efficiently using
10C++ in embedded projects.
11
12These recommendations are subject to change as the C++ standard and compilers
13evolve, and as the authors continue to gain more knowledge and experience in
14this area. If you disagree with recommendations, please discuss them with the
15Pigweed team, as we're always looking to improve the guide or correct any
16inaccuracies.
17
18Constexpr functions
19===================
20Constexpr functions are functions that may be called from a constant
21expression, such as a template parameter, constexpr variable initialization, or
22``static_assert`` statement. Labeling a function ``constexpr`` does not
23guarantee that it is executed at compile time; if called from regular code, it
24will be compiled as a regular function and executed at run time.
25
26Constexpr functions are implicitly inline, which means they are suitable to be
27defined in header files. Like any function in a header, the compiler is more
28likely to inline it than other functions. Marking non-trivial functions as
29``constexpr`` could increase code size, so check the compilation results if this
30is a concern.
31
32Simple constructors should be marked ``constexpr`` whenever possible. GCC
33produces smaller code in some situations when the ``constexpr`` specifier is
34present. Do not avoid important initialization in order to make the class
35constexpr-constructible unless it actually needs to be used in a constant
36expression.
37
38Constexpr variables
39===================
40Constants should be marked ``constexpr`` whenever possible. Constexpr variables
41can be used in any constant expression, such as a non-type template argument,
42``static_assert`` statement, or another constexpr variable initialization.
43Constexpr variables can be initialized at compile time with values calculated by
44constexpr functions.
45
46``constexpr`` implies ``const`` for variables, so there is no need to include
47the ``const`` qualifier when declaring a constexpr variable.
48
49Unlike constexpr functions, constexpr variables are **not** implicitly inline.
50Constexpr variables in headers must be declared with the ``inline`` specifier.
51
52.. code-block:: cpp
53
54 namespace pw {
55
56 inline constexpr const char* kStringConstant = "O_o";
57
58 inline constexpr float kFloatConstant1 = CalculateFloatConstant(1);
59 inline constexpr float kFloatConstant2 = CalculateFloatConstant(2);
60
61 } // namespace pw
62
63Function templates
64==================
65Function templates facilitate writing code that works with different types. For
66example, the following clamps a value within a minimum and maximum:
67
68.. code-block:: cpp
69
70 template <typename T>
71 T Clamp(T min, T max, T value) {
72 if (value < min) {
73 return min;
74 }
75 if (value > max) {
Ali Zhangf22f1f12021-04-02 18:59:28 -070076 return max;
Keir Mierle2c1e56b2019-11-15 16:32:11 -080077 }
78 return value;
79 }
80
81The above code works seamlessly with values of any type -- float, int, or even a
82custom type that supports the < and > operators.
83
84The compiler implements templates by generating a separate version of the
85function for each set of types it is instantiated with. This can increase code
86size significantly.
87
88.. tip::
89
90 Be careful when instantiating non-trivial template functions with multiple
91 types.
92
93Virtual functions
94=================
95Virtual functions provide for runtime polymorphism. Unless runtime polymorphism
96is required, virtual functions should be avoided. Virtual functions require a
97virtual table, which increases RAM usage and requires extra instructions at each
98call site. Virtual functions can also inhibit compiler optimizations, since the
99compiler may not be able to tell which functions will actually be invoked. This
100can prevent linker garbage collection, resulting in unused functions being
101linked into a binary.
102
103When runtime polymorphism is required, virtual functions should be considered.
104C alternatives, such as a struct of function pointers, could be used instead,
105but these approaches may offer no performance advantage while sacrificing
106flexibility and ease of use.
107
108.. tip::
109
110 Only use virtual functions when runtime polymorphism is needed.
Wyatt Hepler63afc002021-02-08 13:20:26 -0800111
112Compiler warnings
113=================
114Bugs in embedded systems can be difficult to track down. Compiler warnings are
115one tool to help identify and fix bugs early in development.
116
117Pigweed compiles with a strict set of warnings. The warnings include the
118following:
119
120 * ``-Wall`` and ``-Wextra`` -- Standard sets of compilation warnings, which
121 are recommended for all projects.
122 * ``-Wimplicit-fallthrough`` -- Requires explicit ``[[fallthrough]]``
123 annotations for fallthrough between switch cases. Prevents unintentional
124 fallthroughs if a ``break`` or ``return`` is forgotten.
125 * ``-Wundef`` -- Requires macros to be defined before using them. This
126 disables the standard, problematic behavior that replaces undefined (or
127 misspelled) macros with ``0``.
128
129Unused variable and function warnings
130-------------------------------------
131The ``-Wall`` and ``-Wextra`` flags enable warnings about unused variables or
132functions. Usually, the best way to address these warnings is to remove the
133unused items. In some circumstances, these cannot be removed, so the warning
134must be silenced. This is done in one of the following ways:
135
136 1. When possible, delete unused variables, functions, or class definitions.
137 2. If an unused entity must remain in the code, avoid giving it a name. A
138 common situation that triggers unused parameter warnings is implementing a
139 virtual function or callback. In C++, function parameters may be unnamed.
140 If desired, the variable name can remain in the code as a comment.
141
142 .. code-block:: cpp
143
144 class BaseCalculator {
145 public:
146 virtual int DoMath(int number_1, int number_2, int number_3) = 0;
147 };
148
149 class Calculator : public BaseCalculator {
150 int DoMath(int number_1, int /* number_2 */, int) override {
151 return number_1 * 100;
152 }
153 };
154
155 3. In C++, annotate unused entities with `[[maybe_unused]]
156 <https://en.cppreference.com/w/cpp/language/attributes/maybe_unused>`_ to
157 silence warnings.
158
159 .. code-block:: cpp
160
161 // This variable is unused in certain circumstances.
162 [[maybe_unused]] int expected_size = size * 4;
163 #if OPTION_1
164 DoThing1(expected_size);
165 #elif OPTION_2
166 DoThing2(expected_size);
167 #endif
168
169 4. As a final option, cast unused variables to ``void`` to silence these
170 warnings. Use ``static_cast<void>(unused_var)`` in C++ or
171 ``(void)unused_var`` in C.
172
173 In C, silencing warnings on unused functions may require compiler-specific
174 attributes (``__attribute__((unused))``). Avoid this by removing the
175 functions or compiling with C++ and using ``[[maybe_unused]]``.