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.
8 thoughts on “Emulating C11 compiler features with gcc: _Generic”
Just wanted to let you know
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 returns
void, same behaviour, but feels wrong.
Anyway, great to have this.
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
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
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 of
P99_GENERICto gcc, anyhow.)
I will push a new release with that solution later today.
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.
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, &Amatches
struct 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.
new version works fine, thanks for taking care.
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.
PS: please use
[sourcecode][/sourcecode]tags when you include larger code snipsets in a comment
I saw I was missing proper initialization, still the p99-2012-01-28 version was somewhat inconsistent:
I did not expect
to compile, and the result returned by it was somewhat off my expectations too.
Looking on the cpp results
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:
While the error returned by gcc does not match the information cpp has
it’s enough to see something is wrong.
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?
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.
Comments are closed.