In the firmware and embedded software engineering domains, engineers overwhelmingly choose C as their language of choice. Evidence of this may be seen in the following screen-grab of a presentation by Dan Saks at CppCon2016.
I would recommend the entire presentation, which may be found here: https://youtu.be/D7Sd8A6_fYU
Selecting C over C++ is a reasonable and conservative choice, especially given that some microcontrollers only support C. However many projects now support C++ and thanks to gcc, many now support modern C++11 or newer standards.
For this post, I’m going to follow Dan’s advice and avoid arguing. I am simply going to describe a few reasons I have come to prefer working on C++11 based embedded software or firmware projects.
The ability to guarantee that a data structure is initialized consistently, correctly, and automatically is important and a key benefit of moving from C to C++. There have been too many times where I have written or encountered legacy C code that did not properly initialize a structure before its use. This isn’t really specific to C++11, but pairs nicely with the next item.
Destructors are another C++ feature which is not specific to C++11 but critical to my use of C++ in embedded software. Clean up, shut down, close, whatever is appropriate to your object. Destructors enable handling many of these cases automatically. Constructors and destructors are absolutely required for my number one top reason for moving to C++, RAII.
RAII (Resource Allocation Is Initialization)
RAII is certainly one of the worst acronyms ever. But, the concept it represents is generally my top reason for selecting C++ in my embedded software projects, especially projects that make use of threads. Why? Here is a pseudo code example without RAII:
Notice the multiple UNLOCK() calls associated with each return point? Here is the same code in C++ using the RAII pattern.
Notice all the UNLOCK() calls disappear and are replaced by a single C++ object called MyMutexLocker. MyMutexLocker is designed such that its constructor locks the mutex and its destructor unlocks the same mutex. No errors. No code maintenance issues induced by someone forgetting to unlock the mutex before returning from the function, etc.
In multi-threaded code developed with traditional resource sharing, RAII is my number one reason for wanting to use C++.
By the way, C++11 offers a formalized version of the above pattern for locking a mutex. See std::lock_guard.
Of course this pattern is not limited to dealing with mutexes. For example, I have used the RAII pattern to enable scoped performance measurements. Once the class is implemented, a user simply creates a performance measuring object within the scope of code to be measured. The object’s constructor will start a timer or note a timestamp and the destructor stops the timer while also recording the timed results. Once implemented, such a class enables easy performance measurements which only further encourages the monitoring and validation of the performance of the software being developed.
User-defined literals are another favorite tidbit in C++11. Here is a quick sample of what this C++11 feature enables.
C-style code creating a define:
C++11 with a special _MPH user-defined literal:
I have written about their usefulness in improving code readability in the past, take a look here for full details: Favorite Tools: C++11 User-defined literals.
I can’t help it, but I love having a formally defined “nullptr” keyword in C++11. No more NULL macros. Sometimes it is the little things in life that matter. 🙂
C++11 (and apparently C11, which I discovered while editing this section) adds a formally defined “static_assert” method to its arsenal of useful tools. I use static_assert every chance I get. Examples? Perhaps the code implements an internal private look up table where a public enum is used as the index into the table. What happens if a future maintainer of the software adds or removes from the enum but is not aware of the lookup table? static_assert to the rescue! What if the code defines data structures shared across multiple projects and/or multiple applications and we want to remind future maintainers to consider backward compatibility when changing such structures? Again static_assert to the rescue. I love a good static_assert. And it turns out I have written about my love of static_asserts in the past, please see here for more details.
std::array is fundamentally a C array, but type safe and better integrated into the C++ world. Once a project has transitioned to C++11, my arrays tend to become std::arrays. That being said, old habits die hard, and sometimes I still catch myself declaring an array as a normal C-style array. Thankfully, when I slip up, it is generally trivial to convert a C array to a C++11 std::array. I have written about the std::array class before: check out my article on embeddedrelated.com.
Someone with many years of hard-core C experience may be forgiven for perhaps being daunted by the idea of moving to C++. C++ is a complex multi-paradigm language with its own international standard where we see the concepts of “template metaprogramming” combined with object oriented programming, generics, and of course, standard procedural programming. There is a great deal to learn. Don’t worry about it. Read a bit. Learn a bit. And then start. Start by writing C-style code with the C++ compiler instead of the C compiler. Become familiar with the new warnings and errors induced by C++ type checking. Use a namespace to encapsulate your module instead of prefixing every public function API with a fixed identifier. Perhaps one day there is a need to copy existing code to change some data type, perhaps from floating point math to integer math? Consider using C++’s generic template programming paradigm. Creating a C-style struct? Consider constructors to help ensure the structs are always initialized correctly. And with each step, each new experience, search google, check stackoverflow, and confirm the best practices on the topic before writing too much new code. I would also recommend some bed side reading material. Here are a few great books on C++ that I have found very useful:
Questions? Let me know in the comments or send me an email. Glad to be of service!