C/C++ Contributing Editors


Standard C/C++: Revising Standard C

P. J. Plauger

While all the attention has been focused on developing the first C++ Standard, others have been quietly revising Standard C. Here is some of the early history of that effort.


ANSI committee X3J11 took over six years to develop the current standard for the programming language C. The project began in mid 1983 and did not result in formal adoption until late 1989. The C Standard was thus known for a time as X3.159/1989. About a year later, ISO adopted an essentially identical draft as the International Standard for C. Its friends now call it ISO/IEC 9899:1990. The programming community has thus enjoyed nearly a decade of stability in the specification of one of its most important programming languages.

ISO rules call for an International Standard to remain unchanged for a minimum of five years. The user community can adapt only so fast to evolving standards. Many enterprises feel that five years is barely long enough to get comfortable with a given specification. Equally, those of us who develop standards typically need about that long to recover from the last round of committee meetings, public reviews, drafting sessions, and so forth. At the very least, we need time to earn enough to pay for our volunteer efforts.

At the end of that five-year "time out," ISO SC22 asks its members to make one of three recommendations:

For an actively used language, the third option is the most likely recommendation. But believe it or not, all three options are exercised regularly, even in the turbulent world of data-processing standards.

The process of revision itself takes several years. Up until recently, three ballots were required within ISO to accept the revised draft. Each of these ballots would yield public commentary that had be addressed. The process has recently been streamlined, but it is still a nontrivial exercise, involving technical review and balloting among many of the National Bodies that participate in ISO standards development. So the customary pattern is for a major language to pop up in a substantially new form only every eight or more years. Consider Algol 60 and 68, or Fortran 66, 77, and 9X, as just two examples.

When we finished the C Standard, many of us were looking forward to that lull in the action of five or more years. (Some of us vowed rashly never to get involved in drafting a programming-language standard ever again.) We were content to interpret the existing standard, tie up a few loose ends, and explore a few informal ways that C might be enhanced among those with special interests.

Unconventional Forces

But these are turbulent times. Uses for computers have exploded in recent years. Consequently, the community of programmers now numbers in the millions. Standard C is an important tool, but it is far from the only one. Many of those programmers care more about some particular dialect of C offered by a major vendor than they do about Standard C. Some still program in older languages because Standard C doesn't quite meet their needs. That's partly why the Numerical C Extensions Group (NCEG or X3J11.1 in various past guises) spent several years exploring ways to extend Standard C.

And then there is C++.

Just as the work on standardizing C was settling down, interest began to bloom in C++. In many ways, of course, this was inevitable. Standards bring stability, which programming shops need. But programmers also need some way to experiment, to try new ideas. C++ brought object-oriented capabilities to the C community at an opportune moment. Computers had become large and fast enough that the overheads were often unimportant, and programming projects had become large enough that the extra structure of classes was often sorely needed.

But at least as important was the fact that C++ was still evolving, while C was frozen. It is easier to experiment with a malleable compiler, one with no sharply defined specification, than with one that must also adhere to a precise standard. And additions don't have to be confined to the realm of object-oriented techniques — indeed, much of what has been added to C++ in recent years is only loosely related to that discipline. Consider STL, as an extreme example. It is much more a tour de force of "generic" programming than an object-oriented approach.

All the better for C++ that it inevitably sits atop C (and often Standard C in the bargain). A portable and efficient base language eases the porting of the C++ superstructure to numerous platforms. Projects with tons of "legacy" C code can plan transitions to C++ in relatively small steps over a period of years. And components with critical performance or reliability requirements can remain in C indefinitely.

C++ has enjoyed an extended adolescence. It did not succumb to final standardization until late in 1997. For a long time, it was able to shirk many of the responsibilities of a stand-alone programming language. It pointedly rebelled at the stodgier parts of its heritage, even as it has benefited from them in various ways. In a very real sense, C++ has been able to depend on the presence of its staid parent to pay the rent and keep gas in the car.

As a partial consequence, C++ continued to evolve aggressively even as it was being standardized. ISO WG21 and ANSI X3J16 struggled with conflicting goals. Keep C++ compatible with Standard C, but let it evolve as a language in its own right. Add all the "missing bits" before the language freezes, but freeze the language soon enough to provide some overdue stability for the user community. It was a difficult line to walk.

But even with an occasional misstep, C++ has made significant strides. It is still growing in importance, as well it should. An important issue among more conservative programming shops is the considerable added complexity that comes with switching from C to C++. Some make the change in the hope that the payoff will exceed the cost. Some resist any change in the fear that the opposite will occur. Many would like a safer intermediate course.

Exploring New Conventions

Even in the early 1990s, it became clear to many of us that Standard C risked being rendered prematurely obsolete by the rapid pace of events. (Many C++ afficionadoes consider this outcome both inevitable and desirable, but not all of us believe that it best serves the needs of the entire programming community.) Waiting until 1995 to begin revising the C Standard appeared to greatly enhance that risk.

I believe that is why, in large measure, WG14/X3J11 voted unanimously in December 1993 to begin immediately the process of revising Standard C. A strong sentiment among committee members was that a revised C should steer that intermediate course between current Standard C and the emerging Standard C++. We knew that it would still take years to make a new C Standard, and the process would certainly not lead to any formal change before the 1995 statutory review date. But we saw that the active revision of Standard C would have several salutary effects:

Taking such a path was not without its risks. The revision process could easily open floodgates. We knew that many of the neat ideas that didn't make it into the current C Standard would be trotted out again. Every then current dialect of C had extensions that warranted consideration. And we knew that some people would insist that C is not complete until it subsumes all of the major features of C++.

Then there were all those eager new C programmers with fresh ideas for "improvements." It is much too easy for a committee to compromise by adding features, rather than hold out for an integrated design. Adding a large and disorderly set of extensions can swamp a reasonably bounded and practical language.

The fact is, there are few forces at work that make a language smaller. Removing any feature, however archaic, almost always results in a loss of backward compatibility. Any minority can successfully argue against such changes. Standard C has only a few deprecated features — things put on notice as candidates for future deletion. The rest form a long tail that will ever be part of C.

So the joint committee WG14/X3J11 knew that it could begin the process with the best of intentions, then lose control of it. If that were to happen, and C lost its integrity, we would all lose in the end.

Then there is the tight relationship between C and C++. For the standardization of C++, this acted primarily as a brake on the inventiveness of WG16/X3J16. From the outset, ISO put this joint committee on notice that it had better not introduce gratuitous incompatibilities between C and C++. Those incompatibilities that do exist were required to be documented and defended.

So what should happen if there are suddenly two moving targets? Even in the early 1990s, nobody expected the C++ Standard to freeze until at least 1994 or 1995. Each joint committee could rightfully feel ill used if the other introduced incompatibilities. Neither joint committee had a strong case for getting the final say in any disputes. Nor is SC22 at all inclined to referee technical disputes between two of its Working Groups.

Well, in point of fact the problem already existed. The C Standard was evolving all this time, in the guise of Amendment 1. Mostly, Amendment 1 constitutes an extensive addition to the Standard C library, in an area hardly addressed by current implementations of C++. The C++ Standard eventually adopted all of Amendment 1, along with the rest of the Standard C library, as the basic underpinnings of the Standard C++ library.

A more controversial corner involved adding certain "digraphs" to C as alternate spellings for certain operators and punctuators. Early on, the C++ standardization effort jumped the gun and adopted a preliminary version of the digraph proposal. For a period of time, there were mild recriminations back and forth about whose version should take precedence in the end. (The two versions are still not entirely in agreement, but close enough.)

Still, there was no question but that coordination would be that much harder once C woke up and really got rolling. The problems would be at least as political as they are technical, but that certainly wouldn't make them any easier to solve.

Establishing Conventions

All these concerns were legitimate, but we on the C committees knew they could be mitigated. WG14/X3J11 approached the coming revision with caution. The first step, in fact, was for the joint committee to produce a "Charter" that outlined the goals of the revision. This is a statement of scope, and of intent, for the process that was to follow. While it could hardly be considered binding — a committee can always vote to reverse itself on alternate Tuesdays, if it chooses — it could provide important moral clout in keeping the revision of Standard C more tightly focused.

The Charter has much the same role as the introduction to the original Rationale for the ANSI C Standard. That document emphasizes the importance of portability, efficiency, and compatibility with existing practice, for example. It argues that all implementations can be made to change, favoring no particular one as being most exemplary. At the same time, it argues that existing code should not have to suffer gratuitous changes to track the evolution of the language standard.

A Charter for revision has to go even further. It must delineate the kinds of changes that are considered necessary or desirable, and the kinds that aren't. The latter statement serves as the first line of defense against the complexifiers, those who want to add just one more cute bit of notation to C. (It is by no means a sufficient defense, but it is a necessary part of it.)

One principle clearly agreed upon by members of the joint committee was that C should indeed evolve in the direction of closer compatibility with C++. The trick, of course, was to pick up the best bits without acquiring an excess of complexity or a notable loss of performance — and without becoming just an unimportant dialect of C++. (The catch phrase for the C++ standardization effort has long been, "As close as possible to C, but no closer." The corresponding phrase for the C revision was now, "Closer to C++ than you thought possible, but not too close.")

There were a few "gimmees," of course. Double slash as a comment delimiter has long appeared in many C compilers. Tighter type checking seems to be mostly a good idea. (The macro NULL is effectively dead, in practice, as a result.) In fact, many of the things touted as making C++ "a better C" warranted close examination. It was the fancier additions that needed more careful analysis.

Here, I hoped we could profit from a decade or more of experience with C++ and other object-oriented languages. Bob Jervis, original author of the Borland Turbo C compiler, had been experimenting in recent years with object-oriented additions to C-like languages. He presented to the C committees what I considered to be a very good first cut at what's worth keeping and what's not.

So what should go into an "object-oriented" revision of Standard C? Classes, most definitely. Polymorphism (virtual functions), okay too. But multiple inheritance? Not very likely. The complexities soar for just a little extra capability. Just adding back what Jervis identified with this first cut would, I felt, turn a wealth of C++ code into C code.

I soon got my chain yanked. The C committees were even more conservative than I expected. Or maybe I had become more infected with the invention bug than I realised from my time spent with the C++ committees. In any event, practically all the proposals for making C look more object-oriented soon fell by the wayside. There might be support for making Standard C look more like Fortran, but not much support for making it look more like C++.

There was more to revising Standard C than mining C++ for ideas, good or otherwise. C++ refuses to be a proper superset of Standard C. Equally, Standard C cannot confine itself to being a proper subset of C++. Certainly NCEG had done much useful work over a period of years. Not everything they propose could automatically be included in a revised C, but all of it deserved careful consideration. And the C community is broad and diverse — we could not confine proposed additions too narrowly. A complete Charter would certainly have to provide guidelines for adding things that are not a part of C++.

Here is where the politics got really tricky. How do you allow Standard C to evolve in its own right in the presence of such a closely related effort for C++? The answer lay in what I called the principal of the Largest Common Subset. It allows both languages to evolve separately, but in ways that don't gratuitously interfere with mutual compatibility.

The idea is to keep this common subset as large as possible, or even to enlarge it where that makes sense. Where one language wants to make unique extensions, it should not arbitrarily encroach on the common subset. Where the subset must be made smaller, the offending party has a strong obligation to provide a compelling rationale.

My belief was and is that maintaining the Largest Common Subset is a reasonable principle to impose on both the C and C++ joint committees. It is the sort of thing that can be made sufficiently objective to head off most confrontations even before they bite. It can serve as a guideline for reconciling the conflicts that will still arise. And it is the sort of thing that SC22 can accept as a treaty point between two of its Working Groups. Indeed, SC22 recently gave explicit permission for the two languages to diverge, but with the implicit understanding that the divergence should not be gratuitous.

Doing the Work

For a variety of reasons, I chose to resign as Convener of WG14 in late 1996. My role in the actual revision of the C Standard has been reduced to that of observer. I can report, as a keen observer of the process, that WG14 and X3J11 (now J11) have behaved most responsibly in following through on the original Charter. They were even more conservative than I had hoped, as I indicated above, but that is probably for the good of the C community as a whole.

The committees early on established a timetable that calls for the revised C Standard to be accepted before the end of 1999. Thus, they adopted the abbreviated term C9X to distinguish the revision from the existing C Standard, which is sometimes called C89. So far, it looks like the timetable will be met. C9X will not suffer from a Y2K problem.

I've intentionally confined myself to history and justification of the C9X effort in this installment. In coming months, I'll go into more detail about what you can expect when C9X becomes official. I can tell you now that you'll find considerable backward compatibility with existing Standard C. The new stuff mostly takes the form of bolt ons. But there are enough new features that the explaining will take some effort. Bear with me.

P.J. Plauger is Senior Editor of C/C++ Users Journal and President of Dinkumware, Ltd. He is the author of the Standard C++ Library shipped with Microsoft's Visual C++, v5.0. For eight years, he served as convener of the ISO C standards committee, WG14. He remains active on the C++ committee, J16. 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.