C99#IEEE 754 floating-point support
{{short description|C programming language standard, 1999 revision}}
{{About|the programming language dialect}}
{{Use dmy dates|date=January 2021}}
{{missing information||_Pragma(), FP_CONTRACT, CX_LIMITED_RANGE|date=November 2020}}
{{C language revisions}}
Image:ISO-IEC-9899-1999-cover.png
C99 (previously C9X, formally ISO/IEC 9899:1999) is a past version of the C programming language open standard.{{cite web|url=https://www.iso.org/iso/iso_catalogue/catalogue_ics/catalogue_detail_ics.htm?csnumber=29237 |title=ISO/IEC 9899:1999 - Programming languages - C |publisher=Iso.org |date=2011-12-08 |access-date=2014-04-08}} 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.{{cite web |url=https://grouper.ieee.org/groups/754/meeting-materials/2001-07-18-c99.pdf |title=IEEE 754 Support in C99 |website=IEEE |archive-url=https://web.archive.org/web/20171028003206/http://grouper.ieee.org/groups/754/meeting-materials/2001-07-18-c99.pdf |archive-date=2017-10-28 |access-date=2021-07-15}} 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
C99 is, for the most part, backward compatible with C89, but it is stricter in some ways.{{cite web|url=https://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Standards.html |title=Standards - Using the GNU Compiler Collection (GCC) |publisher=Gcc.gnu.org |access-date=2014-04-08}}
In particular, a declaration that lacks a type specifier no longer has int
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 int
. In practice, compilers are likely to display a warning, then assume int
and continue translating the program.
C99 introduced several new features, many of which had already been implemented as extensions in several compilers:{{cite web|url=https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html |title=C Dialect Options - Using the GNU Compiler Collection (GCC) |publisher=Gcc.gnu.org |date=2009-05-06 |access-date=2014-04-08}}
- 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
long long int
, optional extended integer types, an explicit Boolean data type, and acomplex
type 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
//
, as in BCPL, C++ and Java - new library functions, such as
snprintf
- new headers, such as
<stdbool.h>
,<complex.h>
,<tgmath.h>
, and<inttypes.h>
- type-generic math (macro) functions, in
, which select a math library function based uponfloat
,double
, orlong double
arguments, etc. - improved support for IEEE floating point
- designated initializers. For example, initializing a structure by field names:
struct point p = { .x = 1, .y = 2 };
{{cite web |url=https://gcc.gnu.org/onlinedocs/gcc-3.3/gcc/Designated-Inits.html |title=Using the GNU Compiler Collection (GCC): Designated Initializers |website=gnu.org |access-date=18 September 2019}} - compound literals. For instance, it is possible to construct structures in function calls:
function((struct x) {1, 2})
{{cite web |url=https://gcc.gnu.org/onlinedocs/gcc-3.3/gcc/Compound-Literals.html |title=Using the GNU Compiler Collection (GCC): Compound Literals |website=gnu.org |access-date=31 January 2016}} - support for variadic macros (macros with a variable number of arguments)
restrict
qualification allows more aggressive code optimization, removing compile-time array access advantages previously held by FORTRAN over ANSI C{{cite web |url=https://lwn.net/Articles/255364/ |title=What every programmer should know about memory |date=2007-10-23 |access-date=2015-04-03 |author=Ulrich Drepper |publisher=LWN.net}}- universal character names, which allows user variables to contain other characters than the standard character set: four-digit {{code|\u0040}} or eight-digit hexadecimal sequences {{code|\U0001f431}}
- keyword
static
in array indices in parameter declarations{{cite book | url=https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf | title=ISO/IEC 9899:1999 specification, TC3 | at=p. 119, § 6.7.5.3 Function declarators (including prototypes) para. 7}}
Parts of the C99 standard are included in the current version of the C++ standard, including integer types, headers, and library functions. Variable-length arrays are not among these included parts because C++'s Standard Template Library already includes similar functionality.
IEEE 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 754-1985 (also known as IEC 60559) floating-point hardware present in the vast majority of modern processors (defined in "Annex F IEC 60559 floating-point arithmetic"). Platforms without IEEE 754 hardware can also implement it in software.
On platforms with IEEE 754 floating point:
{{unordered list
|1= float
is defined as IEEE 754 single precision, double
is defined as double precision, and long double
is defined as IEEE 754 extended precision (e.g., Intel 80-bit double extended precision on x86 or x86-64 platforms), or some form of quad precision where available; otherwise, it is double precision.
|2= The four arithmetic operations and square root are correctly rounded as defined by IEEE 754.
{{(!}} class="wikitable floatright" style="margin-left: 1.5em; font-family:monospace;"
{{!-}}
! FLT_EVAL_METHOD !! float !! double !! long double
{{!-}}
{{!}}0{{!!}}float{{!!}}double{{!!}}long double
{{!-}}
{{!}}1{{!!}}double{{!!}}double{{!!}}long double
{{!-}}
{{!}}2{{!!}}long double{{!!}}long double{{!!}}long double
{{!)}}
|3= Expression evaluation is defined to be performed in one of three well-defined methods, indicating whether floating-point variables are first promoted to a more precise format in expressions: FLT_EVAL_METHOD == 2
indicates that all internal intermediate computations are performed by default at high precision (long double) where available (e.g., 80 bit double extended), FLT_EVAL_METHOD == 1
performs all internal intermediate expressions in double precision (unless an operand is long double), while FLT_EVAL_METHOD == 0
specifies each operation is evaluated only at the precision of the widest operand of each operator. The intermediate result type for operands of a given precision are summarized in the adjacent table.}}
FLT_EVAL_METHOD == 2
tends to limit the risk of rounding errors affecting numerically unstable expressions (see IEEE 754 design rationale) and is the designed default method for x87 hardware, but yields unintuitive behavior for the unwary user;{{cite web|url=https://www.validlab.com/goldberg/addendum.html|title=Differences Among IEEE 754 Implementations|author=Doug Priest|year=1997}} FLT_EVAL_METHOD == 1
was the default evaluation method originally used in K&R C, which promoted all floats to double in expressions; and FLT_EVAL_METHOD == 0
is also commonly used and specifies a strict "evaluate to type" of the operands. (For gcc, FLT_EVAL_METHOD == 2
is the default on 32 bit x86, and FLT_EVAL_METHOD == 0
is the default on 64 bit x86-64, but FLT_EVAL_METHOD == 2
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;{{cite web|url=https://drdobbs.com/architecture-and-design/184410314 | title=A conversation with William Kahan. | author=Jack Woehr |date=1 November 1997}} 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:
- include
- include
- include
- include
- include
- include
- include
double compute_fn(double z) // [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)
{
#ifndef __STDC_IEC_559__
puts("Warning: __STDC_IEC_559__ not defined. IEEE 754 floating point not fully supported."); // [9]
#endif
#pragma STDC FENV_ACCESS ON
#ifdef TEST_NUMERIC_STABILITY_UP
fesetround(FE_UPWARD); // [10]
#elif TEST_NUMERIC_STABILITY_DOWN
fesetround(FE_DOWNWARD);
#endif
printf("%.7g\n", compute_fn(3.0));
printf("%.7g\n", compute_fn(NAN));
return 0;
}
Footnotes:
- Compile with: {{code|lang=bash|1=gcc -std=c99 -mfpmath=387 -o test_c99_fp test_c99_fp.c -lm}}
- As the IEEE 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
STDC
are defined in the C standard.) - 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.
- The special values such as NaN and positive or negative infinity can be tested and set.
long double
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{{cite web |url=https://www.cs.berkeley.edu/~wkahan/ieee754status/baleful.pdf |title=The Baleful Effect of Computer Benchmarks upon Applied Mathematics, Physics and Chemistry| author=William Kahan |date=11 June 1996}} (the typedefdouble_t
can be used for code that is portable under allFLT_EVAL_METHOD
s).- 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
FLT_EVAL_METHOD
is defined as 2 then all internal computations including constants will be performed in long double precision; ifFLT_EVAL_METHOD
is defined as 0 then additional care is need to ensure this, including possibly additional casts and explicit specification of constants as long double.) - 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.
- 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).
__STDC_IEC_559__
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).- 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
TEST_NUMERIC_STABILITY_UP
etc. in this example, when debugging) can be used to diagnose numerical instability.{{cite web|url=https://www.cs.berkeley.edu/~wkahan/Mindless.pdf | title=How Futile are Mindless Assessments of Roundoff in Floating-Point Computation? | author=William Kahan |date=11 January 2006}} This method can be used even ifcompute_fn()
is part of a separately compiled binary library. But depending on the function, numerical instabilities cannot always be detected.
Version detection
A standard macro __STDC_VERSION__
is defined with value 199901L
to indicate that C99 support is available. As with the __STDC__
macro for C90, __STDC_VERSION__
can be used to write code that will compile differently for C90 and C99 compilers, as in this example that ensures that inline
is available in either case (by replacing it with static
in C90 to avoid linker errors).
- if __STDC_VERSION__ >= 199901L
/* "inline" is a keyword */
- else
- define inline static
- endif
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.{{cite web |website=Ars Technica |url=https://arstechnica.com/information-technology/2013/06/c99-acknowledged-at-last-as-microsoft-lays-out-its-path-to-c14/ |title=C99 acknowledged at last as Microsoft lays out its path to C++14 |author=Peter Bright |date=29 June 2013 |access-date=9 January 2015}} However, with the introduction of Visual C++ 2013 Microsoft implemented a limited subset of C99, which was expanded in Visual C++ 2015.
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.{{cite web|url=https://gcc.gnu.org/onlinedocs/gcc/Standards.html |title=Standards - Using the GNU Compiler Collection (GCC) |publisher=Gcc.gnu.org |access-date=2014-04-08}} 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
{{Portal|Computer programming}}
- C++23, C++20, C++17, C++14, C++11, C++03, C++98, versions of the C++ programming language standard
- Compatibility of C and C++
- C++ Technical Report 1
- Floating point, for further discussion of usage of IEEE 754 hardware
References
{{Reflist}}
Further reading
- [https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf N1256] (final draft of C99 standard plus TC1, TC2, TC3); WG14; 2007. ([https://port70.net/~nsz/c/c99/ HTML and ASCII versions])
- [https://www.iso.org/standard/29237.html ISO/IEC 9899:1999] (official C99 standard); ISO; 1999.
- [https://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf Rationale for C99]; WG14; 2003.
- {{cite journal|last=Cheng|first=Harry|title=C99 & Numeric computing|journal=Dr. Dobb's Journal|url=https://drdobbs.com/cpp/184404993|date=1 March 2002}}
- {{cite web|url=https://www.ibm.com/developerworks/library/l-c99.html|title=Open source development using C99|last=Seebach|first=Peter|date=24 March 2004|work=developerWorks|publisher=IBM}}
External links
- [https://www.open-std.org/jtc1/sc22/wg14/www/wg14_document_log.htm C Language Working Group 14 (WG14) Documents]
- [https://www.open-std.org/jtc1/sc22/wg14/www/docs/historic/n444.htm C9X Charter] - WG14
- [https://www.open-std.org/jtc1/sc22/wg14/www/newinc9x.htm New things in C9X]
- [https://www.cplusplus.com/articles/iz3hAqkS/ Features of C99]
{{S-start}}
{{S-bef| before = C89 / C90 / "ANSI C"}}
{{S-ttl| title=C language standards}}
{{S-aft| after = C11}}
{{end}}
{{CProLang}}
{{ISO standards}}
Category:C (programming language)
Category:Programming language standards