Should you use C++ for an embedded project?
Recently I was asked whether to use C or C++ for an embedded project. Let’s assume a sizeable project with an ARM7-based microcontroller and roughly 16KB of RAM. Here is my answer, and I hope it’s useful for you.
One good reason to go with C++ might be that you have a ready team of programmers who are already fluent in it. This would be a strong pull, but if they are not fluent in the embedded world particularly, then this article may help them choose a subset of C++ suitable for an embedded environment.
As the guy said, C makes it easy for you to shoot yourself in the foot, but C++, being much more complex and powerful, allows you to blow your whole leg off. This is true especially in embedded situations.
If you’ve only used C for embedded projects, you’ll be able to get started and into the project much more quickly if you stick with C, and other people could take over more easily. You won’t spend time learning the ins and outs of C++.
C has the advantage of being very direct and “what you see is what you get”. For example, in C this line of code adds two numbers together:
int x = y + z;
But in C++ a very similar-looking line:
MyType x = y + z;
This calls a constructor (which could do anything), calls the + operator of y’s class which (if overloaded) could do anything, possibly throws an exception, possibly allocates memory, etc. You just don’t know, unless your coding style guide lays down the law about what you can and can’t do (more on that soon).
On the other hand, there are definitely some good features in C++’s favour that make programming better, especially for larger projects. Classes, namespaces, templates, scoping … but the language has a ton of powerful features as well as quirks, so when you’re embedding C++ you have to choose a subset of the language and stick with it.
For instance, for embedding C++ in an ARM7-sized processor, you might come up with a list something like:
- Use function overloading, default arguments, and references.
- Use namespaces and classes.
- Use templates for specific things X, Y, and Z.
- Use RAII and scoping for things like allocation, locking, etc.
- Use inheritance and virtual functions, but sparingly, only as required.
- Use C++ style casts, but not
dynamic_cast
.
- Don’t use
new
, exception on boot-up. Don’t usedelete
. Use storage pools and “placement new” where appropriate. - Don’t use the STL (Standard Template Library).
- Don’t use exceptions or run-time type information.
- Don’t do operator overloading (far too many quirks and memory management problems).
- Don’t use friends or friend classes.
If you haven’t used C++ before, you’ll definitely want to learn it before getting too far in. Following some links in my C++ blog articles may be helpful here:
- C++ for C programmers, part 1 of 2 — the non-object oriented features
- C++ for C programmers, part 2 of 2 — the OO features
- RAII, AC/DC, and the “with” statement
- Protothreads and C++ — protothreads (lightweight pseudo-threads) are useful for embedded systems
That said, you can’t learn it just by reading about it, so you need to start coding.
In conclusion, for a small embedded job I’d pick C first for its simplicity, directness, and the fact more people know it. For a larger project, I’d pick C++ — it can make embedded life nicer, but only if you carefully choose a subset and have a good coding standard.
Further reading:
- Abstraction and the C++ machine model [PDF] — a paper by the creator of C++ on using C++ in embedded systems
- C++ for Embedded: Dos and Don’ts [PDF] — an article with some good points above moving from C to C++ for embedded code
- Linus Torvalds’ rant on why Linux isn’t written in C++ — some good points, but not a level-headed discussion of the topic
20 January 2011 by Ben 5 comments
5 comments (oldest first)
Thanks, Todd. Those are some really helpful recommendations.
Can you elaborate your answer on «Don’t use delete. Use storage pools and “placement new” where appropriate.» phrase?
@Volkan, sure. “Placement new” is a way of telling new not to allocate memory straight from the heap, but use a location (or memory allocation method) that you choose. This is useful for 1) allocating a hardware register-driven object at a specific memory address, and 2) using storage pools.
Storage pools are handy for example if you’re writing a driver for a packet-based protocol, and want to allocate packet buffers of the same size from a larger pool of memory. This means you can keep track of memory allocation/deallocation of the packets, and eliminate memory fragmentation, among other things.
There’s much more about this in Marshall Cline’s C++ FAQ:
Very interesting article, however it can be kind of confusing with all the different aspects depending on the approach or project that you are working on. Thanks for an interesting article!! :-)
Here’s the response I wrote in my coding standard. The short answer is yes and it can be done quite successfully:
Then there’s more specific recommendations.