Besides the new interfaces for threads and atomic operations that I already mentioned earlier, others of the new features that come with C11 are in reality already present in many compilers. Only that not all of them might agree upon the syntax, and especially not with the new syntax of C11. So actually emulating some these features is already possible and I implemented some of them in P99 on the base of what gcc provides: these are
_Static_assert) to make compile time assertions (a misnomer, again!)
_Alignof) to get the alignment constraint for a type
_Alignas) to constraint the alignment of objects or
structmembers. Only the variant that receives a constant expression is directly supported. The variant with a type argument can be obtained simply by
_Noreturn) to specify that a function is not expected to return to the caller
_Thread_local) for thread local storage
_Genericfor type generic expression.
The most interesting among them is probably the latter feature, type generic expressions.
Gcc already has three builtins that can be used to something like
__typeof__(EXP)gives the type of the expression
__builtin_types_compatible_p(T1, T2)is true if the two types are compatible
__builtin_choose_expr(CNTRL, EXP1, EXP2)choose between the two expressions at compile time.
This only gives binary decisions and not multiple ones like
_Generic but with a good dose of
P99_FOR we can come to something that resembles a lot. (I spare you the details of the implementation.) The syntax that we support is as follows
#include "p99_generic.h" #define P99_GENERIC(EXP, DEF, ...) <some nasty use of P99 and gcc builtins>
For example as in the following
P99_GENERIC(a, , // empty default expression (int*, a), (double*, x));
That is an expression
EXP, followed by a default value
DEF, followed by a list of type value pairs. So here this is an expression that depending on the type of a will have a type of
double* that will be set to
In C11 syntax, the above would be coded with some kind of “label” syntax:
_Generic(a, int*: a, double*: x);
As you can see above, the default value can be omitted. If so, it is replaced with some appropriate expression that should usually give you a syntax error.
Here is an example with a default expression that will be used when none of the types matches:
uintmax_t max_uintmax(uintmax_t, uintmax_t); int max_int(int, int); long max_long(long, long); long long max_llong(long long, long long); float max_float(float, float); double max_double(double, double); a = P99_GENERIC(a + b, max_uintmax, (int, max_int), (long, max_long), (long long, max_llong), (float, max_float), (double, max_double))(a, b);
In C11 syntax
a = _Generic(a + b, default: max_uintmax, int: max_int, long: max_long, long long: max_llong, float: max_float, double: max_double)(a, b);
Here all the expressions evaluate to a function specifier. If
a + b is
int, … or
double the appropriate maximum function is chosen for that type. If none of these matches, the one for
uintmax_t is chosen. The corresponding function is then evaluated with
b as arguments.
- Because the choice expression is
a + bits type is the promoted common type of
b. E.g for all types that are narrower than
short, normally int will be the type of the expression and
max_intwill be the function. If
doublethe result would be
The return type of the
_Genericexpression is a function to two arguments. If it would be for
int, e.g, the type would be
int ()(int, int). So the return type of the function call would be
intin that case.
- The arguments are promoted and converted to the expected type of the chosen function.
NB: if the compiler is already C11 complying, the
P99_GENERIC expression will just be translated to the corresponding
Otherwise only gcc and compatible compilers are supported.
Addendum: Today I checked out the new version of clang and discovered that their new version 3.1 that came out in December already supports
_Generic directly. Well done.