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(or_Static_assert) to make compile time assertions (a misnomer, again!)alignof(or_Alignof) to get the alignment constraint for a typealignas(of_Alignas) to constraint the alignment of objects orstructmembers. Only the variant that receives a constant expression is directly supported. The variant with a type argument can be obtained simply byalignas(alignof(T)).noreturn(or_Noreturn) to specify that a function is not expected to return to the callerthread_local(or_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 _Generic:
__typeof__(EXP)gives the type of the expressionEXP__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 int* or double* that will be set to a or x, respectively.
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 a and b as arguments.
- Because the choice expression is
a + bits type is the promoted common type ofaandb. E.g for all types that are narrower thanint, e.gshort, normally int will be the type of the expression andmax_intwill be the function. Ifawould beunsignedandbwould bedoublethe result would bedoubleas well. -
The return type of the
_Genericexpression is a function to two arguments. If it would be forint, e.g, the type would beint ()(int, int). So the return type of the function call would beintin 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 _Generic expression.
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.

Just wanted to let you know
P99_GENERICrocks.Just one thing, it would be great if the default value would allow something to abort compiling, like
currently I use
assert("fail")as default which is of incorrect type, as it returnsvoid, same behaviour, but feels wrong.Anyway, great to have this.
Comment by Markus — January 30, 2012 @ 00:23
You probably mean something like
static_assertsince this would be a compile time error, no?The idea of
_Genericas by C11 is that there is automatically an error, if no default is given and none of the choices triggers. This should be the case here, too, since then you have an empty expression that messes up the syntax completely.To improve the error message one could in effect add a
_Pragma. Something like_Pragma("message \"Invalid choice in type generic expression\"")Unfortunately giving diagnostics through pragmas is not standard, this version here would work for gcc and Co. But other compilers should at least give you a diagnostic for an unknown
#pragma.Comment by Jens Gustedt — January 30, 2012 @ 07:31
Actually a solution with
_Pragmawill not work, because this always gives the diagnostic, regardless of the actual choice expression. But I found another solution that is a bit more sophisticated and uses a gcc extension, namely error attributes to functions. (Using gcc features is not a restriction since we are talking of the mapping ofP99_GENERICto gcc, anyhow.)I will push a new release with that solution later today.
Comment by Jens Gustedt — January 30, 2012 @ 11:17
I created a snippet to demonstrate my problem with default values.
For me, if there is no default value, it does not work at all, even matching generics end up being NULL instead.
#include "p99_generic.h" struct field { void *next; }; struct msg_B { struct field *fields[5]; }; struct msg_A { struct field *fields[4]; }; #define field_X_of_msg(x) \ ((struct field *) \ P99_GENERIC(x, \ assert("msg lacks field by definition"), \ (struct msg_A *, (x)->fields[0]) \ )) #define field_Y_of_msg(x) \ ((struct field *) \ P99_GENERIC(x, \ , \ (struct msg_B *, (x)->fields[0]) \ )) int main(void) { struct msg_A A; struct msg_B B; struct field*fA=field_X_of_msg(&A); struct field*fB =field_Y_of_msg(&B); printf("%p %p\n",fA,fB); fB = field_Y_of_msg(&A); printf("%p %p\n",fA,fB); return 0; }Now,
0x7f70f1658c48 (nil) & 0x7f70f1658c48 0x7fff2394d620is not what I expected, but maybe it is my expectations?Actually I’d expect this to fail during compiling, as you said the default is empty, and nothing matches, so fail?
0x7f70f1658c48 (nil)is wrong to me as the generic for fB should have matched,0x7f70f1658c48 0x7fff2394d620, &Amatchesstruct msg B *?It works when I use a default value, static_asserts do not work here, assert does, as the return value mismatches and can’t be casted properly.
Comment by Markus — January 30, 2012 @ 20:49
new version works fine, thanks for taking care.
Comment by Markus — January 30, 2012 @ 21:06
Thanks to you for testing and giving feedback. Glad that this works, now.
For the values that you saw printed. These were the “correct” ones. You didn’t initialize your variables. The corresponding members that you printed were just uninitialized pointers. If I initialize the variables correctly (
P99_INITcomes handy) it prints(nil) (nil)for the first print.Jens
PS: please use
[sourcecode][/sourcecode]tags when you include larger code snipsets in a commentComment by Jens Gustedt — January 30, 2012 @ 21:14
I saw I was missing proper initialization, still the p99-2012-01-28 version was somewhat inconsistent:
#include <p99/p99_generic.h> struct field { void *next; }; struct msg_B { struct field *fields[5]; }; struct msg_A { struct field *fields[4]; }; #define field_X_of_msg(x)\ ((struct field *)P99_GENERIC(x,\ (void),\ (struct msg_A *, (x)->fields[0])\ )) #define field_Y_of_msg(x)\ ((struct field *)P99_GENERIC(x,\ /* empty default */,\ (struct msg_B *, (x)->fields[0])\ )) int main(void) { struct msg_A A; struct msg_B B; memset(&A,1,sizeof(struct msg_A)); memset(&B,2,sizeof(struct msg_B)); struct field *fA = field_X_of_msg(&A); struct field *fB = field_Y_of_msg(&B); printf("A %p B %p\n",&A, &B); printf("fA %p fB %p\n",fA,fB); fA = field_Y_of_msg(&A); printf("fA %p fB %p\n",fA,fB); return 0; }I did not expect
to compile, and the result returned by it was somewhat off my expectations too.
Looking on the cpp results
// cpp generic.c -Ip99-2012-01-28/ fA = ((struct field *)__builtin_choose_expr (__builtin_types_compatible_p(__typeof__ (&A), struct msg_B *), ((&A)->fields[0]), &(const volatile struct { int p00_v; }){ .p00_v = 0 } ));I think the zero default value for 2012-01-28 was wrong, but well, it is fixed for me in 2012-01-30, which can be seen here:
// cpp generic.c -Ip99-2012-01-30/ fA = ((struct field *)__builtin_choose_expr (__builtin_types_compatible_p(__typeof__ (&A), struct msg_B *), ((&A)->fields[0]), p00_invalid_type_in_generic("generic.c" ":45" ": invalid type generic choice `" "&A" "` for " "(struct msg_B *, (&A)->fields[0])") ));While the error returned by gcc does not match the information cpp has
it’s enough to see something is wrong.
Thanks again.
Ah, not to forget, if you want to use the snippet for a regression test, it is all yours.
- I would have used the tags, but I was unable to find a link for the syntax – maybe I would see a syntax menu bar if I had js on?
Comment by Markus — January 31, 2012 @ 08:09
Yes, probably was too naive.
It is very difficult to force gcc to spit out useful error diagnostics for all the cases. After all, this is just an emulation of the feature.
What you see is the fallback diagnostic when
P99_GENERICis used as a statement or full expression. If it is used as part of another expression, you’d basically see what you have seen through the preprocessor.The diagnostic when it is used in a global declaration context is even worse. It just tells that there is a function call where a compile time expression is expected. I guess we have to live with that for the time being.
No, in the menu you just have simple editing features, but not that one. This is one of the features of wordpress that you’d have to know about.
Jens
Comment by Jens Gustedt — January 31, 2012 @ 08:39