Global Sources
EE Times-India
Stay in touch with EE Times India
EE Times-India > Embedded

Understanding C++14 in embedded systems (Part 2)

Posted: 23 Feb 2015     Print Version  Bookmark and Share

Keywords:C  programmer  code size  malloc  ROM 

Having detailed the implementation of the main C++ language features in Part 1 of this series, we can now evaluate C++ in terms of the machine code it generates. Embedded system programmers are particularly concerned about code and data size; we need to discuss C++ in these terms.

How big is a class?
In C++, most code is in class member functions and most data is in objects belonging to these classes. C++ classes tend to have many more member functions than a C programmer would expect to use. This is because well-designed classes are complete and contain member functions to do anything with objects belonging to the class that might legitimately be needed. For a well-conceptualized class, this number will be reasonably small, but nevertheless larger than what the C programmer is accustomed to.

When calculating code size, bear in mind that modern linkers can extract from object files only those functions that are actually called, not the entire object files. In essence, they treat each object file like a library. This means that unused non-virtual class member functions have no code size penalty. So a class that seems to have a lot of baggage in terms of unused member functions may be quite economical in practice.

Although class completeness need not cause code bloat for non-virtual functions, it is reasonable to assume that all virtual functions of all classes used in a system will be linked into the binary.

How big is an object?
The size of an object can be calculated by examining its class (and all its base classes). Ignore member functions and treat the data the same as for a struct. Then add the size of a pointer if there are any virtual functions in the class or base classes. You can confirm your result by using the sizeof operator. It will become apparent that the combined size of objects in a system need be no greater than the size of data in a C-based procedural model. This is because the same amount of state is needed to model a system regardless of whether it is organized into objects.

C++ and the heap
Heap usage is much more common in C++ than in C. This is because of encapsulation. In C, where a function requires an unknown amount of memory, it is common to externalize the memory as an input parameter and leave the caller with the problem. This is at least safer than mallocing an area and relying on the user to free it. But C++, with its encapsulation and destructors, gives class designers the possibility (and responsibility) of managing the memory used by objects of that class.

This difference in philosophy is evident in the difference between C strings and a C++ string class. In C, you get a char array. You have to decide in advance how long your string can be and you have to continuously make sure it doesn't get any bigger. A C++ string class, however, uses 'new' and 'delete' to allow a string to be any size and to grow if necessary. It also makes sure that the heap is restored when the string is destroyed.

The consequence of all this is that you can scrape by in an embedded system written in C without using 'malloc' and 'free', but avoiding 'new' and 'delete' in C++ is a much bigger sacrifice.

The main reason for banning heap usage in an embedded application is the threat of heap fragmentation. As the software runs, memory allocations of different sizes are acquired and released. The situation can arise where many small allocations are scattered through the heap and, although a large fraction of the heap may be available for use, it is all in small fragments and it is not possible to provide an allocation bigger that the largest fragment.

In an embedded system that runs continuously for years, heap fragmentation may occur only under certain conditions a long time after deployment, and may have been missed in test coverage.

Heap fragmentation can be avoided by using a non-fragmenting allocator. One solution is to re-implement operator 'new' and operator 'delete' using a collection of fixed-size buffer pools. Operator 'new' returns the smallest available buffer that will satisfy the request. Since buffers are never split, fragmentation (or external fragmentation to be precise) does not occur. Disadvantages of this technique are that it uses more memory and that it must be configured to provide the right number of the right sized buffers.

1 • 2 • 3 • 4 • 5 • 6 • 7 Next Page Last Page

Comment on "Understanding C++14 in embed..."
*  You can enter [0] more charecters.
*Verify code:


Visit Asia Webinars to learn about the latest in technology and get practical design tips.


Go to top             Connect on Facebook      Follow us on Twitter      Follow us on Orkut

Back to Top