The C language is a very old, going back to the days before personal computers, before the time of operating systems as we currently know them.
It was devised in the early 1970s as a systems implementation language, a way to avoid having to program an operating system entirely in machine or assembly code; the name comes from its predecessor, B. At the time it was designed, both computer memory and processing time were very valuable commodities, and so the classic terseness of C was born.
The first real standardisation to the language was done in the late 80s; in 1989 ANSI (American National Standards Institute) published its standard, while in 1990 ISO revised the standard. Between them, this new standard of the C language became known as C89. Every compiler which is available today supports this standard, whatever platform or operating system it’s on.
In the intervening years, C not so much matured as started to show its age with its lack of features found in modern languages, such as single-line comments, declare-anywhere variables, and a number of other important features; in the meantime, C++ had grown up and was now a full superset of C – because of this, many programmers switched over from C to C++ simply by renaming .c files to .cpp and letting the compiler do the rest of the work. That wasn’t good enough for some people, though – there were people who were still writing operating systems, and they needed to keep using pure C; they couldn’t use C++ with all its exceptions and complex workings. For them, they created workarounds to the limitations of C by typedef’ing and macros and a number of other ‘hacks’.
In fact, even C++ had a fairly important limitation which only becomes apparent when you try and do systems-level programming; it lacks a precise definition of its data types! For most uses this isn’t a problem – after all, who usually cares whether an ‘int’ can hold 16 million or 4 billion, either way it’s a big number which you’re only likely to hit if you’re doing scientific or financial work. For systems people, though, it is a problem – for example the ATA system is defined by having a number of commands which take a structure consisting of a number of 32-bit elements. So, how to represent a 32-bit integer? The solution has typically been to typedef a u_int32_t as an ‘unsigned int’, which has worked and should continue to work in the future. However, some unlucky souls decided to gamble on a ‘long’ being 32-bit, which was unwise even as long ago as 1993 when DEC created the 64-bit Alpha CPU. What we are seeing as we move into a world of a single platform having both 32-bit (x86) and 64-bit (x86-64) architectures is code which used to work is now failing due to short-sighted programmers and standards committees.
So what has this all got to do with the C language, you may ask? Well, in 1999 the ISO committee in charge of the C standard re-convened and overhauled updated the language in a number of places. While a lot of this was simply bringing it up-to-date with C++ with regards to comments, variable declaration and the like, it also added a number of incompatible new features. A couple of these, such as named structure initialisation (eg struct FILE f = {.fsize=0};) and variable-length arrays (eg int f1(int bsize) { char buffer[bsize]; }) were handy to have, the systems folk finally got a standard way to express integer sizes. Although they are still usually implented as typedefs, people using C99 now have access to several new integral types, including (but not limited to) int8_t, int16_t, int32_t and even int64_t. This means that programmers don’t have to second-guess future developments in machine architecture; by using one of the predefined types they are sheltered from new technologies. The addition of a 64-bit data type is a nod to the gcc people who for many years used an unofficial ‘long long’ as a way to represent a 64-bit number – C99 adds it as an official type in addition to having the int64_t specifier.
With all the advantages C99 appears to have over C89, you’d be mistaken for thinking the compiler writers would have gone running to update their compilers to take advantage of the new features; after all, many of them had unofficial support for them in the form of compiler-specific extensions, so it should be relatively straightforward to bring their compiler into compliance. Unfortunately, while the GNU people have done just that, a fairly few big companies seem completely unaware of it. What we’ve seen is the GNU folk bring out version 3 of their suite with incremental support for C99, with support slowly improving until now, at version 3.4 support is relatively complete. Intel have also, as usual, updated their brilliant ICC compiler suite for both Windows and Linux to have C99 support – from what I gather, the compiler itself is fully compliant. With both open-source and commercial sides covered, there are two companies left – Borland and Microsoft, both of whom target the Windows market.
Borland have been very quiet on the compiler side, and I am unaware what (if any) work they’re doing to update it.
I have worked with Visual Studio for a while now, and was disappointed to learn that the 2003 version compiler didn’t have support for C99 – in fact, Microsoft appear to discourage C programming in favour of C++, with a certain effort required to get a raw C file. The excuse they have is that they\’re brought out C# and have thus been fairly busy getting that up and running. I would be disappointed if Microsoft chose to completely abandon C support in their suite, but it looks as though that may happen – if the rumours are true, we may be coerced into only running Managed (C# and C++) code on future versions of Windows.
All in all, I think C99 is a major step forward for the C language – it brings clear advantages over C++ for people who don’t want/need an OO language; it continues to ensure programming in C is a pleasure.