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