Standard C++ endeavors to be all things to all people. But for some applications, less is definitely more.
Introduction
There's a certain irony here. I'm writing these words just after committees SC22/WG21 and X3J16 have voted out the draft C++ Standard for balloting within ISO. It looks like Standard C++ is at last settling down to something resembling stodgy predictability. But what I'm about to describe is a dialect of C++ that intentionally deviates from this brand new Standard in several significant ways. So much for predictability.
No, I'm not reporting on a rebellion. Quite the contrary. This new dialect is the end product of a deliberate and responsible effort that began in Tokyo over a year ago. I was one of the fortunate few gaijin invited to witness this effort from the outset. I even got to make a few suggestions along the way. Some of them even got incorporated into the final result.
The dialect is called Embedded C++ (or EC++ for short). It is aimed primarily at the needs of programmers who write embedded systems those software products buried deep inside numerous electronic gadgets. Your new car probably has a dozen or more microprocessors under the hood these days. Your microwave oven certainly does. Even the keyboard on your desktop likely has a very simple processor inside it to debounce your keystrokes and sort out double key depressions. From singing greeting cards to city-wide traffic-control systems, the world is becoming awash with embedded systems.
C++ is not likely to be useful on the small end of this range. Four-bit and eight-bit computers can seldom support even a decent dialect of C. Sixteen-bit computers might do justice to C++ in some cases. But larger embedded systems, with tens of thousands of lines of source code or more, often suffer from the known limitations of C. You can keep track of only so many hundreds of external names before you start tripping over your own feet. Classes impose a very necessary partitioning of larger programs, and assist good program design in many other ways as well.
For all its benefits, however, C++ is not an unalderated boon to embedded systems. Programmers of embedded systems like predictability. A virtue of C is that simple statements almost always generate simple code sequences. Not so in C++, with its constructors, destructors, and overloaded operators. Moving an array declaration inside a loop a simple act of good hygiene in C can cause a dramatic increase in overhead if each element of the array must be constructed and destroyed each time around the loop. And the only way you can avoid such surprises is to go inspect a type definition in some other part of the code.
You can't win the benefits of C++ without incurring some of these conceptual costs, of course. But you can limit the risk. One way to do so is to avoid using those features of the language, and library, that are known to be expensive. The cost can be large program size, unpredictably long execution times, or simply a high error rate in writing code because of excess complexity. A feature may be quite useful in some applications, but not worth the perceived cost when used in embedded systems.
Another way to limit risk is to program in a careful style. Most C++ programmers soon learn that some operations take more code or execution time than others, even though both have the same overall effect. Good programmers naturally tend to favor the more efficient, provided readability and maintainability don't suffer as a result. But embedded systems often push hardware to its limits, if only to get the most from a limited parts budget. What is merely good style is an essential discipline in embedded systems programming.
The Embedded C++ specification thus has two important components. One document describes how C++ is simplified by eliminating the more expensive features. The other document provides a style guide for writing C++ that is relatively safe and efficient.
History
With that brief background, I can now describe how Embedded C++ came into being. Advanced Data Controls Corp. (AdaC) sells C and C++ compilers in Japan, primarily to the embedded systems market. I've dealt with this company since it was founded in the early 1980s to market the C compilers produced by my old company, Whitesmiths, Ltd. AdaC now represents Green Hills Software, a principal supplier of C and C++ compilers for embedded systems. Their customers include the major semiconductor manufacturers in Japan Fujitsu, Hitachi, NEC, and Toshiba.
In November 1995, I was in Tokyo for the ANSI/ISO C++ Standards meeting. My friends at AdaC asked me to stay over an extra day to attend a Friday evening meeting. There, gathered around a table, were representatives of AdaC and the four major companies listed above. Seldom in the US do you see such competitors come together to discuss mutual problems. (Competition is a serious barrier to cooperation here, more so than in Japan, but our antitrust laws raise even further obstacles.) And never have I heard such frankness at a gathering of this nature.
Everyone agreed that night that C++ was becoming important to embedded systems programming. And everyone lamented, in one form or another, the problems inherent in supplying C++ compilers that would make their customers happy. The draft C++ Standard was still a year away from stability of any form, and compiler developers were a long way from incorporating all the changes voted into C++ to date. The clear consensus called for a more modest version of C++ to meet the needs of embedded systems programmers.
That meeting marked the birth of what is now called the Embedded C++ Technical Committee. It also saw the first broad outlines of what has now become Embedded C++, a de facto industry standard subset of the full C++ language and library mandated by ANSI and ISO. I got to attend another meeting on a later visit to Tokyo, but the EC++ Technical Committee met rather more often than that throughout the year. They really worked hard at ironing out the technical details. At the Embedded Systems Conference in San Jose last September, I got the honor of announcing the results of their work. (See "State of the Art: Embedded C++," Embedded Systems Programming, November 1996, for a written version of that talk.)
Since that announcement, I've been working hard on developing the necessary support library for an EC++ compiler. (See our Web site, at http://www.dinkumware.com, for more details.) Green Hills Software has informally announced their intention to modify their C++ compiler to enforce this dialect, and to ship my new library with their new EC++ compiler. This is an open standard (see the Committee's Web site at http://www.caravan.net/ec2plus for technical specifications, and any late-breaking news), so other companies are welcome to supply supplemental or competing products. If e-mail enquiries and Web-site hits are any indication, EC++ has already stirred considerable interest.
The Spec
So just what's in EC++? The easiest way to answer the question is to describe what has been left out.
Begin with CD14882, the draft C++ Standard. The version as of 15 November 1996 is now circulating within ISO committee JTC1/SC22 for balloting as a Committee Draft. That's the last technical review before balloting as a Draft International Standard (DIS), which normally does not result in any changes to the technical content of the draft. Barring any political opposition within SC22, a DIS pretty inevitably becomes an International Standard (IS). And the US has already agreed that the ANSI C++ Standard will be the same as the one adopted by ISO.
I recite this long pedigree to emphasize an important point EC++ is intended to be a (nearly) proper subset of the full ISO C++ Standard. It is not just an attempt to roll back the evolution of C++ to a time when the language was simpler, even though that is in many ways the effect. All the useful clarifications and minor enhancements made to C++ in the process of standardization are a part of EC++ as well.
But what's left out is a significant list of features that have been added to C++ in recent years:
- multiple inheritance
- templates
- exceptions
- namespaces
- run-time type identification
and a few other odds and ends.
Each of these features has been left out for a reason. In some cases, such as multiple inheritance and exceptions, a compiler can generate more efficient code for all translation units if it knows that no part of the program will use the feature. In other cases, such as templates, a programmer can avoid contact with the buggiest parts of new compilers. And in other cases, such as namespaces, the supplied library can avoid design issues still in contention within Standard C++.
A compiler that knows about EC++ isn't absolutely necessary, of course. You can impose your own discipline using any existing compiler. You might even choose to use a few templates, or an occasional exception, even though the EC++ library chooses not to, as I discuss further below. Still, it helps to have a compiler switch that enforces the EC++ dialect, if only to ensure code portability.
One thing you can't live without, however, is a proper EC++ library. The full C++ library makes extensive use of templates and exceptions. Even the simplest use of the standard streams cin or cout drags in an incredible amount of code thanks in large part to the ambitious use of locale objects in Standard C++. Consider the classic "hello world" program:
#include <iostream.h> int main() {cout << "hello world" << endl; return (0); }My implementation of the Standard C++ library, with Microsoft's Visual C++, makes the smallest version of this program I know of, which is still more than 50 Kb. The worst report I've heard, of a competing version on the PC, weighs in at over 1,500 Kb! This is not the stuff of embedded systems programming.
The EC++ library avoids these horrible overheads by reverting to the simpler I/O model of yore. There are no locale objects, no wide-character streams, no templatized streams, strings, or complex numbers. What the programmer typically makes use of is just a handful of headers:
<complex> <new> <fstream> <sstream> <iomanip> <string> <iostream> <strstream>These supply a modernized version of the library that you'd typically find with an early C++ compiler. It just happens to look like a subset of Standard C++.
The subset is not quite a proper one. Some differences are hard to avoid:
- Since EC++ makes no use of exceptions, none of the library declarations have throw specifications. By contrast, many of the library declarations in Standard C++ do.
- The header <complex> defines the two classes float_complex and double_complex. In Standard C++, the equivalent types are spelled basic_complex<float> and basic_complex<double>.
Greater differences exist between any two C++ libraries, these days. So there is nothing here that you can't pave over with an occasional typedef, macro, or conditional preprocessing directive. Still, the subset isn't completely pure.
Listing 1 shows the headers that make up the EC++ library, and the entities they define. Headers such as <cerror> typically just include a corresponding header, such as <error.h>, from the underlying Standard C library. But EC++ doesn't require a full C library, as you might detect from a few notable omissions. Even some of the required functions can be dummies. A system that has no filesystem, for example, can supply a version of fopen that always fails.
If you've used the full Standard C++ library, or if you're a long-time reader of my Standard C/C++ column, you should have at least a nodding acquaintance with the remaining headers as well. I've listed more functionality here than the EC++ Technical Committee has specified so far. Partly that's to flesh out obvious oversights, but I've also added a few things, such as <sstream> and <strstream> that I think are genuinely useful in an embedded environment.
Beyond Embedded
EC++ is interesting in its own right, but I'm excited about another prospect as well. Already, I'm talking to customers who want the EC++ library not for an embedded application, but as a simple but adequate C++ library. After all, EC++ bears a remarkable resemblance to C++ circa 1990 about the time that X3J16 began to expand the language in the process of standardizing it. And C++ was growing rapidly in popularity even then, before templates and exceptions were considered so essential to modern programming.
One major customer intends to standardize internally on a combination of the EC++ library and the Standard Template Library. The two subsets fit rather nicely together, with almost no overlap. To me, the combination is rather like taking the legs and the head from a stone statue whose belly is way too fat to fit through a door. What's left on the other side are the firm foundation and the capstone of something that could prove to be rather attractive.
Whatever the outcome, I'm personally glad that the Japanese have taken the lead in this important area. Standard C++ has grown so large that subsetting is inevitable. I'd rather see people agree on a common subset, even if it's just a de facto standard, than proliferate dialects without bound. I've enjoyed programming in EC++ so far. I don't expect to be alone for much longer. o
P.J. Plauger is senior editor of C/C++ Users Journal. He is the author of the Standard C++ Library shipped with Microsoft's Visual C++, v4.2. For eight years, he served as convener of the ISO C standards committee, WG14. He remains active on the C++ committee, WG21. His latest books are The Draft Standard C++ Library, Programming on Purpose (three volumes), and Standard C (with Jim Brodie), all published by Prentice-Hall. You can reach him at pjp@plauger.com.