SLTF Consulting
Technology with Business Sense

 Home | Bio | Contact Us | Site Map


Is C++ the not-ready-for-prime-time embedded language?

Scott Rosenthal
May, 1992

A great debate is raging between the C and C++ camps over the near-term future of the programming world. On the one hand, the C++ carrot dangling before us promises to revolutionize the software industry with what one compiler vendor (Productivity Products International, Inc.) has trademarked as Software-ICs, complete with databooks for picking and choosing bug-free classes. In addition, proponents claim that programmers will need fewer skills and that application development times will drop at a geometric rate instead of the present arithmetic rate. They see companies creating libraries of Software-ICs to support specialized needs just as PC-board layout houses, board manufacturers and parts distributors produce and sell the physical components for manufacturing computer-based products. It sounds great, but is the embedded world ready for C++? If not, what else can we do now to improve program generation in the embedded world?

C++ Condensed

So many good books exist on C++ that I'm not going to delve into the specifics of the language or it's methodology. If you want detailed information, Ref 1 is an excellent source. In a nutshell, C++ characterizes a different way of approaching programming. To begin with, instead of assuming that you'll write almost all the code for an application from scratch, C++ promises to help you take advantage what you and other developers have previously written by creating reusable classes of software objects. In this sense the language attempts to model how humans learn. For example, if you give a racquetball to a toddler, he calls it a ball. If you give him a basketball, he also calls it a ball because both objects are round, bounce, and he can throw them. The toddler has generalized his world into an easy-to-understand extensible framework. Give this child any object ball-ness criteria and it's a ball until proven otherwise.

C++ allows the programmers to describe not only the actions that objects perform the data but also the objects’ characteristics in terms of the data they contain. In other words, the data items that define a ball's size and color are private to that object, and other functions can't change them. For example, a racquetball is a particular color and size, and only the ball's manufacturer can alter those characteristics. In the same way, when you create an object in C++, the data defining its characteristics become a part of it and C++ saves any changes to that description in the object's private data.

This feature of hiding data from other objects and functions is one key to C++'s power. In order to change its embedded data, an object must possess a member function to manipulate the data. As a case in point, consider the racquetball example mentioned above. One characteristic of racquetballs is that the more times they bounce the less resilient or bouncy they become. To reproduce this effect in a C++ object, the racquetball object would use a predefined algorithm to reduce the ball's springiness each time one of the ball's member functions bounces it. Hence the bounce-height function is localized to one particular object and can only affect that object's data. Imagine how much more complicated this process would be if you spread the control for the bouncing around in fifty different places throughout your code!

A second feature of C++ is that it categorizes objects into classes that describe the class member's common features. Every object belongs to a class, but no classes are objects. In the previous example, the racquetball object belongs to a class called Ball. You can define a new Ball object--called "blurp"--that you can use in the same place as any other Ball object. If your program has a section for simulation the bouncing of a ball, it can bounce a blurp as well as any other Ball object because the mechanism that defines how to bounce a ball in incorporated into the class Ball. The class concept, therefore, means you don't need to program each ball-bouncing function separately for each type of ball.

Another feature of C++ (and all other object-oriented languages) is inheritance. To understand this property of the language consider this question: What's a football? It's a ball with slightly different characteristics. To represent this relationship in C++ you create a class called Football that inherits from the Ball class. All previous characteristics of a Ball are now part of Football, but the new Football class also has some characteristics that set it apart from the Ball class. Hence, instead of coding a new Football class from scratch, you inherit what you can and simply add what's different.

Although there's much more to C++ than I can cover in this brief space, the bottom line is that this language attempts to force you into taking a more global view of the problem space, not just for the particular problem but also for as yet undefined future problems. The ultimate goal for all of C++ features is two-fold. First, you should become a more productive programmer because you produce fewer lines of code to complete a project. Second, the industry can produce high-quality software with less-skilled (and lower-paid) programmers. After all, how much skill does it take to pick an appropriate Software-IC from a databook?

Is it worth the effort?

Unfortunately, for embedded systems the jury is far from being in as to whether converting to C++ is worth the effort. No matter what advertisements might say, that language suffers form limitations that significantly impact its applicability. As anyone who's programmed an embedded system knows, the two scarcest resources are memory and CPU power. C++ uses significant amounts of both. Embedded systems typically have a limited address space compared to PCs and so never seem to have enough memory for the delivered application. Most programmers have spent many hours trying to shoehorn more program into available space. C++ significantly exacerbates this problem.

As an example, I compiled and linked the ubiquitous "hello world" program with a C compiler for my PC. The resulting executable was 3k bytes in size. I then compiled and linked the same program with Ver 2 of the Borland Turbo C++ compiler. Although the only difference between the two programs was that I substituted C++'s "puts" ( << ) operator for the stdio puts() function, the resulting C++ executable was now 18K bytes! The C++ compiler manufacturer argued that the program was so much larger that the C version because the linker had to include all the class hierarchies for resolving the classes built from a base class called Object. They likened this size penalty to the increase you realize from linking in an entire floating-point math library to satisfy one floating-point operation. Further, that firm assured me that in larger applications C++ programs come out ahead because most of the class support functions are already linked in.

To test this point I next built a serial-communications application under both C and C++. The C version required 18K bytes while the C++ application required 90K bytes! Memory nowadays is much cheaper than before, but can an embedded system afford the extra cost? Even if you can afford the memory chips,, does the target processor have the address space necessary to access them? Finally you must consider penalties in compiling, linking and executing larger programs.

Another major problem I've discovered in my search to change my office over to C++ is the lack of compilers for most embedded processors. Sure, if you embed an 80X86 processor or 68XXX you can find C++ compilers to support these chips. But what happens if you chose and uncommon, single-source, chip like the INTEL 80C196KC? Because you can barely find a working C compiler for this chip, I'd be deathly afraid of ever trying a C++ compiler for it. Also, the size of the market always drives the level of tool support. Because C++ compilers and linkers are more complex to write than similar products for C, compiler vendors will either choose not to support the language due to the development costs or release a product the final cost of which is so high that it excludes much of the market.

Don't lose hope

Luckily, alternatives exist that can bypass many of these problems. For example, if you want to use the language for a processor that doesn't have a native C++ compiler, try using a preprocessor that translates a C++ program into standard C code. Although the resulting program will be larger and slower than an equivalent C program, a more important issue is how to debug the code. Specifically, how will a source-level debugger work with C code that you didn't write and that you don't want to patch? You could easily end up spending one hour a day debugging and the other seven trying to figure out what the preprocessor did to the code.

A better alternative might be to simply forget about C++ and object-oriented design for the present: these tools might be the future but they aren't right for the embedded world today. Instead, remember that part of what C++ tries to do is enforce a design methodology that good programmers follow anyway. By developing skill with current tools you can gain most, if not all, of C++'s advantages without any of its limitations. The secret is knowing how to use what's available. Rely on your intelligence, instead of a tool, for creating productive reusable code. To further you in that effort, my next column will show how to use present compilers to build well-designed systems that survive repeated changes and produce code that's usable in other designs--all without giving up the compactness, speed, and flexibility of C. PE&IN

Reference: Stroustrup, B, The C++ Programming Language, Second Edition, Addison-Wesley Publishing Co, Reading, MA, 1991, ISBN 0-201-53992-6.

About Us | What We Do | SSM | MiCOS | Search | Designs | Articles

Copyright © 1998-2014 SLTF Consulting, a division of SLTF Marine LLC. All rights reserved.