P99
P99 - Preprocessor macros and functions for C99 and C11

P99 is a suite of macro and function definitions that ease programming in modern C, aka C99. By using new facilities in C99 we implement default arguments for functions, scope bound resource management, transparent allocation and initialization, ...

By using special features of some compilers and operating systems, we also are able to provide an almost feature complete emulation of the new C standard, C11.

Macros and inline functions working together

In C, functions (whether inline or not) and macros fulfill different purposes. Their difference should not be seen as ideological as some seem to take it, and what is even more important, they may work nicely together.

Macros are text replacement that is done at compile time and they can do things like P99_SIGNED(EXPR) which is defined by P99. That macro takes an expression as an argument, and tells at compile time of whether or not the integral type of EXPR is signed or not. Additionally it guarantees that EXPR itself is not evaluated at run time (so there are no side effects), but that only its type is taken into consideration.

Such an example shows that macros are ideally used when the type of an expression is to be determined and you want to act accordingly to that type. On the other hand, the pitfall with macros is that their arguments may be evaluated several times, which is bad because of side effects.

Functions on the other hand are typed, which makes them more strict or, phrased negatively, less flexible. Consider the function

 inline
 uintmax_t p00_abs_signed(intmax_t a) {
  return (a < 0) ? -(uintmax_t)a : (uintmax_t)a;
 }

It takes signed integer value a and computes its absolute value. Observe that the return type of this function is unsigned. This has to be so, since otherwise not all valid values could be realized.

p00_abs_signed would not be a good candidate for a macro, since a is evaluated twice in the expression; once in the controlling expression and once for returning its value or its negation.

We may use this function with any integral type, but then the result would probably not be what a naive programmer would expect if the argument is a large unsigned value. The argument will be promoted to intmax_t. If the value X that is passed to the call is positive and greater than INTMAX_MAX = 2N -1, the result is probably not what we'd expect. 1 If the conversion to intmax_t doesn't result in a range error thrown by the run time system (it would be permitted to do so), the argument a of the function would receive the negative value -C where C is 2N - X. The result of the function call would then be C and not X.

With the following macro we get rid of these restrictions by combining the macro and the function:

 #define P99_ABS(EXPR) (P99_SIGNED(EXPR) ? p00_abs_signed(EXPR) : (EXPR))

This has the following properties

In that spirit, P99 aims to provide utilities that often combine macros and inline funcions and that are only possible with the features that come with C99 (read ANSI C as normalized in 1999) and that were absent in C89. The features include among others

On some platforms, P99 is also able to emulate the main features that come with the newest C standard, C11:

With all these features it implements utilities that previously had not been possible to program in C (or C macros) or that were very difficult to implement

P99 also provides numerous facilities for macro programming.

P99 is not a C library in the classical sense but merely a collection of include files:

Footnotes:

1 Here N+1 is the width of uintmax_t, assuming most common representations of signed integers.

2 Well, there is exactly one exception to that: on systems where -INTMAX_MIN is not representable in uintmax_t, this same value may cause problems.

Credits and Rights

Author and Maintainer

Author:
Jens Gustedt
Date:
2010 - 2012

Contribution

Author:
William Morris proof reading
Date:
2012

Version

The version this documentation describes can be identified via the macros P99_VERSION_DATE, namely Fri Mar 21 17:48:24 2014 +0100. It also is tagged with an hexadecimal ID tag that is given in P99_VERSION_ID, namely 25e980231040c940906813a487c6979d434c5888.

Copyright

Copyright © 2010-2012 Jens Gustedt, INRIA, France, http://www.inria.fr/

License

 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines