Embedded C++: An Overview

by P.J. Plauger

Is EC++ the diet pill that will shrink C++ down to size for embedded applications? Here's P.J. Plauger's take.

The Fall 1997 Embedded Systems Conference in San Jose was a smashing success. Attendance was way up over last year, and rather more than even the optimistic projections made by the Powers that Be before the conference opened. I haven't seen this much activity and interest in the embedded marketplace ever before. Period.

Of particular interest to me was the attention awarded to Embedded C++. It was only a year earlier, at the Fall 1996 Embedded Systems Conference, that I had the honor of formally introducing this project to the public. It could have sunk without a trace in the intervening months-many optimistic new projects do-but that didn't happen. Quite the contrary, I found growing enthusiasm on several fronts.

I'll elaborate on these themes in the remainder of this article. But first, let me back up and supply a bit of history. I can then fill in the relevant technical details. (See also the sidebar, "Read All About It," for a supplemental reading list.)

HISTORY

I first heard of this project in November 1995, while attending a meeting of WG21 and J16, the ISO and ANSI committees standardizing C++. Advanced Data Controls Corp. (ADaC) is a Japanese company with whom I've done business since their founding in 1982. My friends at ADaC urged me to extend my stay to attend a Friday evening meeting they had arranged. Given the warmth and past success of our business relationship, I didn't hesitate to rearrange my travel plans and attend.

The meeting was astonishing. In addition to the folks from ADaC and a couple of fellow Americans, the attendees included software people from the four major Japanese semiconductor manufacturers-Fujitsu, Hitachi, NEC, and Toshiba. These were the folks responsible for providing software development tools to their customers. They were all wrestling with what to do about C++, and they were very frank about their problems. I have personally never witnessed such an open dialog between nominal competitors, certainly not among American companies. But then, we Americans enjoy a richer fabric of antitrust laws, to keep companies from collaborating unfairly. Or fairly, for that matter.

All four companies shared a common complaint. Their customers-almost all developers of embedded systems using their chips-were beginning to demand C++ compilers. Naturally, the vendors were eager to oblige. All four companies offered some form of a C++ compiler, or were about to. But when customers started using C++, they were largely dissatisfied. They were accustomed to C, had learned to deal with its complexities over assembly language, and had learned to accept its overheads. They were nevertheless surprised and amazed at the added complexities and overheads of C++.

On top of everything else was the dialect problem. C++ has been changing rapidly and steadily for years. "Standardization," a process that normally stabilizes a programming language, began in 1989. But in the case of C++, the standardization process has been used as an opportunity to add significant new capabilities to the language before it freezes. Multiple inheritance, exceptions, templates, and a host of other major features have been added over the past seven years or so, far faster than compiler writers can keep up. As a consequence, every commercial C++ compiler implements a different collection of language features. Moving a C++ program between compilers has become more difficult, not less, as a result of standardization-at least during this transitional period before the draft C++ Standard finally settles down and everyone gets caught up.

It gets worse, at least from the standpoint of embedded systems programming. Several of the new features add significant overheads to a C++ program, in terms of both code size and execution speed. In some cases, the overheads occur even if you don't explicitly make use of the new features. Customers aren't asking for these new features-at least, they haven't yet been educated en masse to want the features-and the chip vendors haven't gotten around to implementing all of them. Compiler development in the commercial world is driven by what customers are asking for this month. There's simply too many things to do to devote product development time in places that don't confer an immediate competitive advantage.

Thus, some of the chip vendors might love to have an excuse not to have to supply, say, exception handling in C++. Many of their customers would happily live without such a feature, at least for the more demanding embedded programming projects. And once the customers discover the overheads associated with exception handling, they may well want to avoid those overheads even if the compiler does support the feature. Equally, the chip vendors don't want to be stigmatized. If the guy down the block sells a compiler with some sexy feature, it's hard to make a case for not providing it as well. Put simply, the vendors face a common software dilemma: how do you make sure that what the customers think they want is also close to what they really need?

A popular solution to such a problem is to define a suitable subset. In this case, we're talking about a subset of the full language and library mandated by the draft C++ Standard. Include in the subset everything that meets the need of embedded systems programmers. Omit anything that arguably can be left out, either because it adds to overheads, or it's too new to be widely available, or for some other good and proper reason. Get a bunch of people to agree on the subset. If several vendors supply the same subset, customers can write C++ code that is both efficient and portable across multiple implementations. Gone is much of the stigma for having less than a full implementation. In its place is, in fact, the cachet of matching a useful standard, even if it's only a de facto industry standard.

Thus was born the idea of Embedded C++ (or EC++, for short) as a dialect aimed squarely at the needs of embedded systems programmers. The group that first came together that Friday night in Tokyo soon dubbed itself the Embedded C++ Technical Committee. Hiroshi Monden of NEC became chair of the committee, and Dr. Kiichiro Tamaru of Toshiba became vice secretary. ADaC is the secretariat. We Americans are merely advisers to the committee, which is very much a Japanese undertaking. The kickoff meeting was conducted mostly in English, as a courtesy to us Americans, who are notoriously weak at discussing technical matters in Japanese. Subsequent meetings were held in Japanese, rather more efficiently for the attendees I might add, throughout much of 1996. The committee maintained a reflector, and did a heckuva lot of work between meetings, in the bargain.

By September 1996, the Embedded C++ Technical Committee had produced a draft specification for their subset. They even had a Web site up and running. (See www.caravan.net/ ec2plus.) As I indicated earlier, I got to make the first public announcement at the Fall 1996 Embedded Systems Conference. The project was out from under wraps and into the marketplace.

THE EC++ LANGUAGE

The Embedded C++ specification is a proper subset of the full draft C++ Standard. Thus, the most economical way to describe it is often in terms of what it doesn't have. I could list all the rules for writing declarations, statements, and expressions, for instance. That might reassure people who love detail that all the things they value about C++ (and C) are still there. But perspective is often lost in details. Saying what has been left out of EC++ is more economical, and often more revealing. Rest assured that what is left is a fully functional subset.

Programming languages such as C and C++ make a fairly sharp distinction between "language" and "library." The compiler is responsible for recognizing the language and generating code that carries out its intent. The library that accompanies the compiler provides a grab bag of classes, functions, and objects likely to be of use in many programs. I begin here by discussing just the EC++ language.

Luckily for me, I was just an adviser to this effort. I can admire the designers for making tough decisions. At the same time, I don't have to take the heat for any controversial choices. It's a nice position to be in, for a change.

THE EC++ LIBRARY

Like the language portion, the Embedded C++ library is often best described in terms of what's missing. Much of what has been omitted from the full draft Standard C++ library must go out of necessity. Thus, there is no need for the header , which works hand in hand with the typeid operator to implement runtime type identification. Keeping the headers and is also hard to justify (though a case can still be made) if the language doesn't support exception handling.

If the language doesn't support templates, then any library template classes or template functions perforce must disappear. In some cases, it makes sense to replace a template class with an ordinary class, or a template function with an ordinary function. But in many cases, the only sensible thing is to just drop the feature from the library. Thus, it's hard to preserve the Standard Template Library when there are no templates. My experience so far is that this is the chunk most sorely missed by programmers contemplating the use of EC++. But more on that topic later.

The iostreams library, on the other hand, began life in pre-standards days as a collection of ordinary classes. The classes became "templatized" a few years ago, as part of a general conversion of the library to make greater use of templates. You can now traffic in streams of "wide characters," in order to support large character sets. You can even presumably invent your own kinds of streams. None of this latitude makes much sense in an embedded environment, however, and the hidden overheads have proven to be enormous. So, EC++ provides classes with the traditional names istream, ostream, and so forth. These classes are not retro artifacts, however. The EC++ iostreams classes behave just like their counterparts in the draft Standard C++ library that are implemented as template specializations.

You'll find a similar treatment of the complex arithmetic classes. You can't write the names complex and complex in a language that doesn't support templates. Instead, EC++ provides the classes float_complex and double_complex with the same behavior. This is one of the few places where EC++ is arguably not a pure proper subset of the full language and library.

A little more surprising is what's left out of the Standard C library. The draft Standard C++ library specification "includes by reference" all of the Standard C library, and then some. It mandates all the added support for wide characters from Amendment 1 to the C Standard. And it overloads a bunch of C functions in the bargain, to be more in keeping with C++ usages. The EC++ library keeps the overloads, but it omits all that extra baggage for supporting wide characters. Japanese developers were the ones who championed this addition to C-you'd think they'd be eager to keep it all. But the embedded community has different needs. Language and library support for wide characters is a luxury in this context.

For a more positive statement of what's actually in the EC++ library, see the sidebar, "EC++ Library Contents."

PERFORMANCE

The proof of the pudding is in the eating, as the saying goes. A fundamental premise behind the design of Embedded C++ is that a subset language can yield greater space and speed efficiencies than the full C++ language. I've probably emphasized too much the need to avoid new language features, out of kindness to implementors and programmers alike. That is a transient problem that should cure itself over the next few years, as the C++ Standard becomes official and stable, compilers catch up with it, and programmers learn how to use the new stuff. But performance issues will continue to be important for embedded systems for many years to come.

I wish I could present here a comprehensive list of benchmark results. My company, Dinkumware, Ltd., has such a project under way, but it is still in the preliminary stages. What I can present are some anecdotal results that I believe to be representative of actual programming situations. They compare relative program sizes for a couple of small test programs compiled in different ways and linked with different libraries.

The two libraries are the Dinkum C++ Library and the Dinkum EC++ Library. The former is a complete implementation of the draft Standard C++ library, in all its gory details. (See Microsoft VC++ v. 5.0 for an earlier version of this library.) The evidence to date is that this is a particularly efficient implementation, at least compared to the current competition. The latter library is Dinkumware's implementation of the Embedded C++ library. We also think it's pretty efficient, but so far we have nothing to compare it to. (See www.dinkumware. com for more information.)

Green Hills Software is a leading vendor of compilers for the embedded marketplace. They license the Dinkumware libraries, in all flavors, for distribution with their compilers. The two test programs were compiled with their PowerPC compiler that is now shipping. They generally observe that program size and execution speed are directly proportional, at least for typical test programs. My experience is that modern microprocessors generally behave this way-execution time depends primarily on the number of bytes of code the processor has to read. Barring hot spots, this is proportional to the total program size. So I show here only relative program sizes.

A small program that makes simple use of library I/O tends to be dominated by the contribution from the library. The relative sizes of such a test program are:

Note first the dramatic savings that occur when the compiler doesn't have to worry about exception-handling code. Your mileage may vary with your compiler, but exceptions are known to exact a significant toll on code size and/or execution speed. Then note what the simpler library gives you. By leaving out unwanted machinery that cannot be avoided in the full C++ library, EC++ weighs in at about half the size. Combine the language and library savings, and you get a program only three-eighths the size of full C++.

The effects are more dramatic for a somewhat larger program that makes greater demands on the library I/O facilities. In this case, it is harder for the full C++ library to avoid loading great quantities of additional code. The relative sizes are:

 


Return to Embedded.com
Send comments to: Webmaster
Copyright © 1998 Miller Freeman, Inc.,
a United News & Media company.