Experience Embedded

Professionelle Schulungen, Beratung und Projektunterstützung

Should I Use C++14 in My Next Embedded Design?

Autor: Bertil Spolander, IAR Systems

Beitrag - Embedded Software Engineering Kongress 2017

EETimes and Embedded.com has an annual market survey [1] which, amongst other things, surveys what programming language the respondents use in their current project and what they are planning to use in their next project. In 2017, C is used by 56% in their current projects and 52% in their next project. The corresponding numbers for C++ is 22% and 24%. No other languages are over 5%.

This corresponds to our own experience at IAR Systems. Our customers, mostly in the MCU market, are using C much more than C++. Even to a higher degree than the survey says.

Why is this? Should those who use C use C++ instead?

To answer this, you need a cost/benefit analysis. What are the benefits of using C++ instead of C, and what does it cost with regards to code size and execution speed? Also, the C++ language has changed a lot with the newer C++ standards C++ 11 and C++ 14. Has anything changed with the newer C++ standards that could or should have an impact on the choice of language?

Benefits of C++

Although C++ is a multiparadigm language, in our experience, the object orientation features of the language are what developers desire when they move to C++. An object oriented design allows for, amongst other things:

  • Better modularity resulting from the ability to couple data with the methods and operators that manipulate it
  • Reuse of code by inheritance - you can have existing code that you can use while still bein able to specialize and enhance it
  • Flexibility through polymorphism - being able to use the same interface to different types of objects makes it easier to maintain stable APIs
  • Higher levels of abstraction where you can hide the implementation to a higher degree

 

If you decide to use an object orientated design, what are the benefits of using C++ instead of other OO languages?

Since C is still the most widely used programming language for embedded systems, it is very likely that embedded programmers know C. And although C++ is not a perfect superset of C, it is close. This makes it easy for a C programmer to gradually move from C to C++. However, there is a risk in this too. Even if you use a C++ compiler, the individual programmer may continue to use a C kind of coding style, since this is still possible.

Another advantage in the common heritage with C is that interfacing with C code is not complicated at all. Whether you have legacy C code that you don’t want to rewrite or you want to use 3rd party libraries written in C.

Also, just like C, C++ is still fairly close to hardware, and even if name mangling and template instantiation will make it harder to correlate your source code with your generated assembly code, it is still doable.

In conclusion, there are significant benefits of using C++ since it is easier and faster to build robust designs that are easier to maintain.

Cost of C++ Features

When I discuss the "cost" of C++ features, it is a cost in different shapes. The most obvious costs are code size and execution speed. But other aspects are important as well, like size of data, predictability of runtime performance and compile times. Also when I talk about free, cheap or expensive, it is mostly related to how a corresponding implementation would have been in C.

Classes

Calling member functions does not use a function pointer stored in the class but instead uses name mangling to incorporate the class name into the function name and then add a pointer to the object as a hidden parameter.

Example (see image, PDF).

Since this is probably exactly how you would implement a corresponding function in C, there is no additional penalty.

Inheritance

Consider these classes (see image, PDF).

An object of class "derived" will be constructed by first taking all members of "base" and then add all members of "derived", no additional pointers to a parent object or other overhead are necessary.

The memory for the derived class will look like this:

b_member1

b_member2

b_member3

d_member1

d_member2

d_member3

 

Virtual functions

 

When using virtual functions to enable polymorphism, the system has to dynamically, at runtime, decide what function to call.

In this case, every object will carry a pointer to a table with the correct virtual functions for that object. Every class with virtual functions will have such a table with one table entry for every virtual function. So the cost is one pointer for every object with virtual functions and one table for all classes with virtual function. Any call to such member function will need to look up the address in the table which will cost a few extra instructions.

Cheap, but not free.

Inlining

Inlining is a compiler optimization which is a straight tradeoff between code size and execution speed. While C has inlining, it is more prevalent in C++, especially since you tend to have many small and simple member functions to access your class. However, if the body of your member functions is smaller than the overhead for the function call, inlining will also be a code size optimization. Use inlining carefully when optimizing for size, and you will have no problems. 

Templates

Templates is a means of generalizing functions or classes based on types. You can have a singular definition of a function or a class and use it for many different types.

Instantiation of templates is a complex operation for the compiler, and it may yield multiple copies of the function. This is a concern regarding mainly code size but also execution speed.

Another problem with templates is that it is fairly easy to build complex structures that are hard to maintain and debug.

Extensive use of templates will be expensive.

Exceptions

The C++ exception handling mechanisms are provided to report and handle errors and exceptional events. There is no corresponding way of doing this in C. Usually, you need every function to return an error value if something has gone wrong, but that will interfere with the functions possibility to return a normal value.

The exception handling in C++ gives you a possibility to design your application in a way that is not possible to do easily in C.

The cost, however, is high. This is due to the fact that the system needs to keep track of possible call chains to be able to return in a controlled manner. This costs data space. Whenever an exception occurs, any objects that are destroyed due to the exception need to have their destructors executed. Thus, the execution time when an exception occurs is potentially long and unpredictable.

Exceptions are expensive, but allow for a different and, in many cases, safer design.

Standard library

The standard library in C++ is vastly bigger and more useful than the standard library for C. It is complex and generic. This has two major impacts:

  1. There are lots of useful functions that are well tested and ready to use, which means less code that the developers need to do themselves.
  2. The generic aspect of the library means that the contained functions are probably not as efficient as if you write the corresponding code yourself and specialize it for your own needs.

 

So you have to decide if the convenience of the library functions are enough to outweigh the possible performance loss.

STL, the Standard Template Library, is a part of the standard libraries that handles different kinds of containers, such as vectors, lists, maps and so on, and corresponding functions to access these containers.

As the title reveals, they are implemented using templates to enable you to use the containers, for instance a vector, with integers, floats or any Class type you have defined yourself.

STLs have the drawbacks I discussed with regards to templates and the ones for the standard library. Therefore, when you are using STL, evaluate whether the convenience and reliability of it is worth the extra cost in code size and execution time.

Added features in C++11 and C++14

Most of C++ bad reputation for embedded systems comes from C++ 98 and earlier. Since then, we have two new standards: C++ 11 and C++ 14. In these standards, there have been additions to both convenience and performance of the language, which in makes C++ and even better and more maintainable language to use and also more efficient.

Move semantics

Also known as rvalue references.

In C++ temporary objects are created copied and destroyed from time to time. And although you can use different programming techniques to limit them, it is hard to eliminate them entirely. Move semantics can make these operations much more efficient by "reusing" the content of the objects.

With copy semantics, the temporary object is created, copied from and then the entire object is destroyed, including any complementary objects that are referenced.

Copy semantics copies the entire object, including references (see image, PDF) and then destroys the original object (see image, PDF).

Move semantics only copies the "base" object (blue), then redirects the copied objects reference to the old "secondary" object (red) (see image, PDF), and then subsequently destroys the old "base" object (see image, PDF).

When the secondary object is large, move semantics can give significantly better execution speed and use less data memory.

Automatic type inference

Instead of writing the explicit type of a variable, you can let the compiler infer the type from the initializer expression. Instead of writing (see image, PDF), you can infer the type for 'it' like this (see image, PDF). Auto can be used instead of a type name in most cases where the compiler can deduce the type of the expression.

New function specifiers (final & override)

These two keywords can be applied to any member functions.

Override indicates that this member function is intended to override a function in a base class. If somebody changes the base function you will get a compile time error. It is a good way to assure that your APIs don’t change without you knowing it.

Final tells the compiler that no subsequent derived class may override this member function that this is the final version of the function. It is a tool to help you to be clear and concise with your APIs. For an example, see image (PDF).

Conclusion

Since embedded applications are becoming more and more complex, you may need a better programming language than C. C++ can be that language. Choose carefully if and when you should use the more expensive features of the language and evaluate whether you should convert to C++.



[1] https://www.embedded.com/electronics-blogs/embedded-market-surveys/4458724/2017-Embedded-Market-Survey

 

Beitrag als PDF downloaden


Implementierung - unsere Trainings & Coachings

Wollen Sie sich auf den aktuellen Stand der Technik bringen?

Dann informieren Sie sich hier zu Schulungen/ Seminaren/ Trainings/ Workshops und individuellen Coachings von MircoConsult zum Thema Implementierung /Embedded- und Echtzeit-Softwareentwicklung.

 

Training & Coaching zu den weiteren Themen unseren Portfolios finden Sie hier.


Implementierung - Fachwissen

Wertvolles Fachwissen zum Thema Implementierung/ Embedded- und Echtzeit-Softwareentwicklung steht hier für Sie zum kostenfreien Download bereit.

Zu den Fachinformationen

 
Fachwissen zu weiteren Themen unseren Portfolios finden Sie hier.