Why I love C++11 for Embedded Software and Firmware (or C++14, or…)

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.

Dan Saks Embedded Language Trends

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.

Constructors

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

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:

void DoSomethingWithSharedResource()
{
   LOCK(mutex);
   bool ok = DoFirstStep();
   if(!ok)
   {
      UNLOCK(mutex);
      return;
   }

   ok = DoSecondStep();
   if(!ok)
   {
      UNLOCK(mutex);
      return;
   }

   FinalStep();

   UNLOCK(mutex);
}

Notice the multiple UNLOCK() calls associated with each return point? Here is the same code in C++ using the RAII pattern.

void DoSomethingWithSharedResource()
{
   MyMutexLocker lock_it_down(mutex);
   bool ok = DoFirstStep();
   if(!ok)
   {
      return;
   }

   ok = DoSecondStep();
   if(!ok)
   {
      return;
   }

   FinalStep();
}

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

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:

#define ALERT_TONE_TRIGGER_VELOCITY   (MPH_TO_METERS_PER_SECOND(80))

C++11 with a special _MPH user-defined literal:

constexpr MetersPerSecond ALERT_TONE_TRIGGER_VELOCITY = 80_MPH;

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.

nullptr

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.  đź™‚

static_assert

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

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.

The transition

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:

Effective C++ by Scott Meyers

Effective Modern C++ by Scott Meyers

The C++ Programming Language by Bjarne Stroustrup

Questions? Let me know in the comments or send me an email. Glad to be of service!

Photo by Magnus Engø on Unsplash

5 comments

  1. Hi,

    I totally agree. Having moved away from C to C++, I never looked back. C is old fashioned, limited and doesn’t help you write complex programs. It is still stuck in 1978. I am surprised to hear that many embedded software engineers are so conservative that they shoot themselves in the foot by sticking to an outdated language.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Discover more from Cove Mountain Software

Subscribe now to keep reading and get access to the full archive.

Continue reading