Home > Articles > Programming > C/C++

C++ Reference Guide

Hosted by

A Tour of C99

Last updated Jan 1, 2003.

If youโ€™re looking for more up-to-date information on this topic, please visit our C/C++ Programming article, podcast, and store pages.

A Tour of C99

The new C standard -- officially known as ISO/IEC 9899:1999 or C99 in short -- contains substantial changes and extensions in both the core language and its standard libraries. These changes don't apply to C++, of course. However, familiarity with them is important for several reasons. First, it's likely that these changes will be incorporated into C++ eventually, either officially (Bjarne Stroustrup has called for merging C++ and C99 into a single language), or as a de-facto initiative of compiler vendors. Second, C++ programmers often work in mixed environments, where C and C++ are used together.

In the following sections, I will focus on C99's new core language features. These include the syntax, the keywords and built-in features. I will address the changes in standard libraries of C99 in a future article.

Borrowings from C++

Some of the newly added features are direct borrowings from C++. These include inline functions, // comments, dispersed statements and declarations, and loop-scoped variables.

inline Functions

The new keyword inline indicates that a function should be expanded inline, if possible. Personally, I doubt that this feature is as useful as it might have been a decade ago. Not only has compiler technology made a quantum leap in code optimization in recent years, but it's also rather easy to misuse inline, thereby degrading performance. Still, under certain conditions C programs can benefit from the performance boost of inline functions. For example:

inline void * allocate(size_t sz)
{
 return malloc(sz);
}

Line Comments

In addition to the traditional block comments, C now supports line-comments that start with the token // and extend up to the end of the line, just as in C++. In practice, many C compilers have supported this feature for years. Now at last it's official.

Dispersed Statements and Declarations

In earlier versions of C, declarations could appear only at a block's beginning, before any other statements. Now it's possible to place declarations freely. The following function demonstrates this. It's C99-compliant. However, pre-C99 compilers will refuse to compile it because the declaration of rank appears after a statement (and because it uses // comments):

void compensations(Employee *emp)
{
 double bonus=155.25;
 double salary;
 salary=employee->salary + bonus;
 int rank; //allowed only in C99
 //.. rest of the code
}

Scope of for-Loop Variables

The scope of variables declared inside a for-statement is now restricted to the loop's body. Thus,

for (int n=0; n<10; ++n)
{
 //statements
}        

is equivalent to:

{
 int n=0;
 for (; n<10; ++n)
 {
  //statements
 }
}

Novel Core Features

In addition to the borrowings from C++, C99 introduces several novel core features. These include variable length arrays, designated initializers, variadic macros, restrict pointers, the long long data type and the __func__ identifier.

Variable-Length Arrays

In C++ and pre-C99 versions of C, an array's size must be a constant integral expression so that it can be calculated at compile-time. In C99, this restriction was relaxed. An array's size must be an integral expression, not necessarily a constant one. This allows you to declare a variable-length array or an array whose size is determined at runtime. For example:

void func(int sz) 
{
 int arr[sz]; // sz ins't const; allowed only in C99
}

The size of arr may be different for every func() call. For example:

int main()
{
 int size;
 printf("enter array's size : ");
 scanf("%d", &size);
 func(size);
}

To support variable-length arrays, C99 adds the notation [*] in a function's parameter list to indicate a variable-length array. In addition, C99 extends the functionality of sizeof. When applied to a variable-length array, it calculates the its size at runtime. In my opinion, this is the most daring change in C99. Not only does it alter the semantics of a built-in operator from compile-time to runtime operation (only when using variable-length arrays), it's also a "quiet change" -- there's no explicit syntactic clue to distinguish between the two forms.

Designated Initializers

Designated initializers enable you to initialize specific members of an aggregate (i.e., an array, struct or union) while leaving the rest of the members with no explicit initializers. For example

int vec[5] = {[1]=10,[3]=20}; // designated initializers

The declaration of vec explicitly initializes members vec[1] and vec[3] to 10 and 20, respectively, while leaving the remaining members without an explicit initializer. struct and union members can be initialized similarly:

struct Employee
{
 char name[20];
 int ID;
 int age;
 FILE *record;
};

Employee emp = {.ID=0, .record=NULL};

The declaration of emp contains designated initializers for ID and record. Note that when using designated initializers, members that have no explicit initializer are automatically zero-initialized. Therefore, emp's members name and age contain binary zeros.

Variadic Macros

Variadic functions or functions taking a variable argument list are rather common in C. For example:

int printf(const char * fmt,...);

C99 also supports variadic macros. A variadic macro looks like this:

#define Trace(...) printf( __VA_ARGS__)

The ellipsis represents a macro's variable argument list. The reserved __VA_ARGS__ name is used for traversing the arguments passed to the macro. When you call Trace() like this:

Trace("Y = %d\n", y);

The preprocessor replaces the macro call with:

printf("Y = %d\n", y);

Because Trace is a variadic macro, you can pass a different number of arguments on every call:

Trace("test"); // expanded as: printf("test");

restrict-Qualified Pointers

C99 introduces a new keyword, restrict that can only be applied to pointers. It indicates that, during the scope of that pointer declaration, all data accessed through it will be accessed only through that pointer but not through any other pointer. By declaring pointers as restricted, the programmer states that they do not refer to the same object. For example, C99 changes the prototype of fopen() to:

FILE *fopen(const char * restrict filename, 
      const char * restrict mode);

restrict enables the compiler to employ certain optimizations based on the premise that a given object cannot be changed through another pointer. For further information about restrict pointers, see the original proposal.

long long Datatype

long long and its unsigned counterpart unsigned long long are new types in C99. A long long variable shall have at least 64 bits. Likewise, the suffixes "LL" or "ll" (and "ULL" and "ull") can be used in constants of type long long and unsigned long long:

long long molecules=10000000000000LL;

The __func__ Identifier

A new identifier, __func__ is implicitly declared if used within a function as:

static const char func[] = "func-name";

where func-name is the user-given name of the function in which the identifier is used. This provides a means of obtaining the current function's name, similar to the __FILE__ and __DATE__ macros. For example:

void myfunc()
{
 printf("you're in %s", __func__);
}

The output from this code should look like this:

you're in myfunc

Obsolete Features

C99 also removes several diehards such as the K&R function declaration style and the denigrated "implicit int" convention.

Obsolescing K&R Function Declaration Style

The K&R function declaration style in the form of

func(n, m) /* return type is unspecified */
int n; double m; /* function parameters */
{
 /*function body*/
}

was used in K&R. It was later replaced by the more common form:

int func(int n, double m) 
{
/*function body*/
}

The K&R function declaration style is obsolescent in C99. This means that compilers are allowed to reject such code or accept it with a warning message. In either case, they aren't allowed to ignore it.

Implicit int

Until C99, if a function had no explicit return type such as

func(int n) 
{
/*function body*/
}

Its implicit return type would be int. Type int is assumed in other contexts where no explicit type is specified. For example:

const x=0; //treated as 'const int' before C99

The implicit int convention has its roots in the early days of C. In C++, it was removed about a decade ago. C99 follows suit by requiring that declarations shall contain an explicit type.

Summary

The changed and extensions shown here are only a representative sample. Other new features include the new keywords _Bool, _Complex and _Imaginary for Boolean variables (at last!), and complex arithmetic. The standard C library has undergone a methodical overhaul, too. It now includes libraries for floating point environment support, a type-generic math and more. For more information about C99, see the following page or refer to the C99 draft rationale.