thumb|180px|Cover of the C99 standards document

C99 (C9X during its development, formally ISO/IEC 9899:1999) is a past version of the C programming language open standard. It extends the previous version (C90) with new features for the language and the standard library, and helps implementations make better use of available computer hardware, such as IEEE 754-1985 floating-point arithmetic, and compiler technology. The C11 version of the C programming language standard, published in 2011, updates C99.

History

After ANSI produced the official standard for the C programming language in 1989, which became an international standard in 1990, the C language specification remained relatively static for some time, while C++ continued to evolve, largely during its own standardization effort. Normative Amendment 1 created a new standard for C in 1995, but only to correct some details of the 1989 standard and to add more extensive support for international character sets. The standard underwent further revision in the late 1990s, leading to the publication of ISO/IEC 9899:1999 in 1999, which was adopted as an ANSI standard in May 2000. The language defined by that version of the standard is commonly referred to as "C99". The international C standard is maintained by the working group ISO/IEC JTC1/SC22/WG14.

Design

thumb

C99 is, for the most part, backward compatible with C89, but it is stricter in some ways.

In particular, a declaration that lacks a type specifier no longer has <code>int</code> implicitly assumed. The C standards committee decided that it was of more value for compilers to diagnose inadvertent omission of the type specifier than to silently process legacy code that relied on implicit <code>int</code>. In practice, compilers are likely to display a warning, then assume <code>int</code> and continue translating the program.

C99 introduced several new features, many of which had already been implemented as extensions in several compilers:

  • inline functions
  • intermingled declarations and code: variable declaration is no longer restricted to file scope or the start of a compound statement (block)
  • several new data types, including <code>long long int</code>, optional extended integer types, an explicit Boolean data type (<code>_Bool</code>), and complex types (<code>_Complex</code> type specifier) to represent complex numbers
  • variable-length arrays (although subsequently relegated in C11 to a conditional feature that implementations are not required to support)
  • flexible array members
  • support for one-line comments beginning with <code>//</code> (like that of BCPL, C++ and Java)
  • new library functions, such as <code>snprintf</code>
  • new headers, such as <code><stdbool.h></code>, <code><complex.h></code>, <code><tgmath.h></code>, and <code><inttypes.h></code>
  • type-generic math (macro) functions, in <code><tgmath.h></code>, which select a math library function based upon <code>float</code>, <code>double</code>, or <code>long double</code> arguments, etc.
  • optional support for IEEE 754-1985 floating point
  • designated initializers. For example, initializing a structure by field names: <syntaxhighlight lang="c" inline>struct X p = { .i = 1, .j = 2 };</syntaxhighlight>
  • compound literals. For instance, it is possible to construct structures in function calls: <syntaxhighlight lang="c" inline>foo((struct X) {1, 2})</syntaxhighlight>
  • support for variadic macros (macros with a variable number of arguments)
  • <code>restrict</code> qualification allows more aggressive code optimization, removing compile-time array access advantages previously held by FORTRAN over ANSI C
  • universal character names, which allows user variables to contain other characters than the standard character set: four-digit or eight-digit hexadecimal sequences
  • keyword <code>static</code> in array indices in parameter declarations: For example, <syntaxhighlight lang="c" inline>void foo(int bar[static 100]);</syntaxhighlight> tells the compiler that every time <code>foo()</code> is called, the passed pointer <code>bar</code> is definitely not null, and points to an array of at least 100 <code>int</code>s.

Some C99 features were excluded from C++, notably variable-length arrays. C++ offers sequential data structures like <code>std::vector<T></code> for similar purposes.

IEEE&nbsp;754 floating-point support

A major feature of C99 is its numerics support, and in particular its support for access to the features of IEEE&nbsp;754-1985 (also known as IEC&nbsp;60559) floating-point hardware present in the vast majority of modern processors (defined in "Annex F IEC 60559 floating-point arithmetic"). Platforms without IEEE&nbsp;754 hardware can also implement it in software. <code>FLT_EVAL_METHOD == 1</code> was the default evaluation method originally used in K&R&nbsp;C, which promoted all floats to double in expressions; and <code>FLT_EVAL_METHOD == 0</code> is also commonly used and specifies a strict "evaluate to type" of the operands. (For gcc, <code>FLT_EVAL_METHOD&nbsp;==&nbsp;2</code> is the default on 32&nbsp;bit x86, and <code>FLT_EVAL_METHOD&nbsp;==&nbsp;0</code> is the default on 64&nbsp;bit x86-64, but <code>FLT_EVAL_METHOD&nbsp;==&nbsp;2</code> can be specified on x86-64 with option -mfpmath=387.) Before C99, compilers could round intermediate results inconsistently, especially when using x87 floating-point hardware, leading to compiler-specific behaviour; such inconsistencies are not permitted in compilers conforming to C99 (annex F).

Example

The following annotated example C99 code for computing a continued fraction function demonstrates the main features:

<syntaxhighlight lang=C line highlight="9,11,13,15,21,23,25,36,42">

  1. include <assert.h>
  2. include <fenv.h>
  3. include <float.h>
  4. include <math.h>
  5. include <stdio.h>
  6. include <stdbool.h>
  7. include <tgmath.h>

double compute_fn(double z) { // [1]

  1. pragma STDC FENV_ACCESS ON // [2]

assert(FLT_EVAL_METHOD == 2); // [3]

if (isnan(z)) { // [4]

puts("z is not a number");

}

if (isinf(z)) {

puts("z is infinite");

}

long double r = 7.0 - 3.0 / (z - 2.0 - 1.0 / (z - 7.0 + 10.0 / (z - 2.0 - 2.0 / (z - 3.0)))); // [5, 6]

feclearexcept(FE_DIVBYZERO); // [7]

bool raised = fetestexcept(FE_OVERFLOW); // [8]

if (raised) {

puts("Unanticipated overflow.");

}

return r;

}

int main(void) {

  1. ifndef __STDC_IEC_559__

puts("Warning: __STDC_IEC_559__ not defined. IEEE 754 floating point not fully supported."); // [9]

  1. endif
  1. pragma STDC FENV_ACCESS ON
  1. ifdef TEST_NUMERIC_STABILITY_UP

fesetround(FE_UPWARD); // [10]

  1. elif TEST_NUMERIC_STABILITY_DOWN

fesetround(FE_DOWNWARD);

  1. endif

printf("%.7g\n", compute_fn(3.0));

printf("%.7g\n", compute_fn(NAN));

return 0;

}

</syntaxhighlight>

Footnotes:

  1. Compile with:
  2. As the IEEE&nbsp;754 status flags are manipulated in this function, this #pragma is needed to avoid the compiler incorrectly rearranging such tests when optimising. (Pragmas are usually implementation-defined, but those prefixed with <code>STDC</code> are defined in the C standard.)
  3. C99 defines a limited number of expression evaluation methods: the current compilation mode can be checked to ensure it meets the assumptions the code was written under.
  4. The special values such as NaN and positive or negative infinity can be tested and set.
  5. <code>long double</code> is defined as IEEE 754 double extended or quad precision if available. Using higher precision than required for intermediate computations can minimize round-off error (the typedef <code>double_t</code> can be used for code that is portable under all <code>FLT_EVAL_METHOD</code>s).
  6. The main function to be evaluated. Although it appears that some arguments to this continued fraction, e.g., 3.0, would lead to a divide-by-zero error, in fact the function is well-defined at 3.0 and division by 0 will simply return a +infinity that will then correctly lead to a finite result: IEEE 754 is defined not to trap on such exceptions by default and is designed so that they can very often be ignored, as in this case. (If <code>FLT_EVAL_METHOD</code> is defined as 2 then all internal computations including constants will be performed in long double precision; if <code>FLT_EVAL_METHOD</code> is defined as 0 then additional care is need to ensure this, including possibly additional casts and explicit specification of constants as long double.)
  7. As the raised divide-by-zero flag is not an error in this case, it can simply be dismissed to clear the flag for use by later code.
  8. In some cases, other exceptions may be regarded as an error, such as overflow (although it can in fact be shown that this cannot occur in this case).
  9. <code>__STDC_IEC_559__</code> is to be defined only if "Annex F IEC 60559 floating-point arithmetic" is fully implemented by the compiler and the C library (users should be aware that this macro is sometimes defined while it should not be).
  10. The default rounding mode is round to nearest (with the even rounding rule in the halfway cases) for IEEE 754, but explicitly setting the rounding mode toward + and - infinity (by defining <code>TEST_NUMERIC_STABILITY_UP</code> etc. in this example, when debugging) can be used to diagnose numerical instability. This method can be used even if <code>compute_fn()</code> is part of a separately compiled binary library. But depending on the function, numerical instabilities cannot always be detected.

Version detection

A standard macro <code>__STDC_VERSION__</code> is defined with value <code>199901L</code> to indicate that C99 support is available. As with the <code>__STDC__</code> macro for C90, <code>__STDC_VERSION__</code> can be used to write code that will compile differently for C90 and C99 compilers, as in this example that ensures that <code>inline</code> is available in either case (by replacing it with <code>static</code> in C90 to avoid linker errors).

<syntaxhighlight lang=C>

  1. if __STDC_VERSION__ >= 199901L

/* "inline" is a keyword */

  1. else
  2. define inline static
  3. endif

</syntaxhighlight>

Implementations

Most C compilers provide support for at least some of the features introduced in C99.

Historically, Microsoft has been slow to implement new C features in their Visual C++ tools, instead focusing mainly on supporting developments in the C++ standards. However, with the introduction of Visual C++ 2013 Microsoft implemented a limited subset of C99, which was expanded in Visual C++ 2015.

|-

| cc65

|

| Full C89 and C99 support is not implemented, partly due to platform limitations (MOS Technology 6502). There is no support planned for some C99 types like _Complex and 64-bit integers (long long).

|-

| Ch

|

| Supports major C99 features.

|-

| Clang

|

| Supports all features except C99 floating-point pragmas.

|-

| CompCert

|

| A certified compiler, formally proved correct. Supports all features except C99 complex numbers and VLA, and minor restrictions on switch statements (no Duff's device).

|-

| cparser

|

| Supports C99 features.

|-

| C++ Builder

| <br/>

|

|-

| Digital Mars C/C++ Compiler

|

| Lacks support for some features, such as <tgmath.h> and _Pragma.

|-

| GCC

|

| , standard pragmas and IEEE 754/IEC 60559 floating-point support are missing in mainline GCC. Additionally, some features (such as extended integer types and new library functions) must be provided by the C standard library and are out of scope for GCC. GCC's 4.6 and 4.7 releases also provide the same level of compliance. Partial IEEE&nbsp;754 support, even when the hardware is compliant: some compiler options may be needed to avoid incorrect optimizations (e.g., <code>-std=c99</code> and <code>-fsignaling-nans</code>), but full support of directed rounding modes is missing even when <code>-frounding-math</code> is used.

|-

| Green Hills Software

|

|

|-

|IBM C for AIX, V6 and XL C/C++ V11.1 for AIX

|

|

|-

|IBM Rational logiscope

|

|Until Logiscope 6.3, only basic constructs of C99 were supported. C99 is officially supported in Logiscope 6.4 and later versions.

|-

| The Portland Group PGI C/C++

|

|

|-

| IAR Systems<br /> Embedded Workbench

|

| Does not support UCN (universal character names). Compiler for embedded targets, such as ARM, Coldfire, MSP430, AVR, AVR32, 8051, ... No x86 targets.

|-

| Intel C++ compiler

| <br />

|

|-

|Microsoft Visual C++

|

|Visual C++ 2012 and earlier did not support C99. <br />Visual C++ 2013 implements a limited subset of C99 required to compile popular open-source projects.<br />Visual C++ 2015 implements the C99 standard library, with the exception of any library features that depend on compiler features not yet supported by the compiler (for example, <tgmath.h> is not implemented).

|-

| Open Watcom

|

| Implements the most commonly used parts of the standard. However, they are enabled only through the undocumented command-line switch "-za99". Three C99 features have been bundled as C90 extensions since pre-v1.0: C++ style comments (//), flexible array members, trailing comma allowed in enum declaration.

|-

| Pelles C

|

| Supports all C99 features.

|-

| Portable C compiler

|

| Working towards becoming C99-compliant.

|-

| Sun Studio

|

|

|-

| The Amsterdam Compiler Kit

|

| A C99 frontend is currently under investigation.

|-

| Tiny C Compiler

|

| Does not support complex numbers. Variable Length Arrays are supported but not as arguments in functions<!--I tried it! -->. The developers state that "TCC is heading toward full ISOC99 compliance".

|-

| vbcc

|

|

|}

<!-- Included in MinGW are extensions to the Microsoft Visual C++ runtime library to support C99 functionality.[ Given the above statement from the MinGW listing, shouldn't MinGW be included in the above list? -->

Future work

Since ratification of the 1999 C standard, the standards working group prepared technical reports specifying improved support for embedded processing, additional character data types (Unicode support), and library functions with improved bounds checking. Work continues on technical reports addressing decimal floating point, additional mathematical special functions, and additional dynamic memory allocation functions. The C and C++ standards committees have been collaborating on specifications for threaded programming.

The next revision of the C standard, C11, was ratified in 2011. The C standards committee adopted guidelines that limited the adoption of new features that have not been tested by existing implementations. Much effort went into developing a memory model, in order to clarify sequence points and to support threaded programming.

See also

  • Compatibility of C and C++
  • C++ Technical Report 1
  • IEEE 754, for further discussion of usage of IEEE 754

References

Further reading

  • N1256 (final draft of C99 standard plus TC1, TC2, TC3); WG14; 2007. (HTML and ASCII versions)
  • ISO/IEC 9899:1999 (official C99 standard); ISO; 1999.
  • Rationale for C99; WG14; 2003.
  • C Language Working Group 14 (WG14) Documents
  • C9X Charter - WG14
  • New things in C9X
  • Features of C99

bg:C (език за програмиране)#C99