C11 - Using Generators

I tried to learn how to use the β€œnew” C11 Generic expressions, but I ran into a wall.

Consider the following code:

#include <stdlib.h> #include <stdio.h> #define test(X, Y, c) \ _Generic((X), \ double: _Generic((Y), \ double * : test_double, \ default: test_double \ ), \ int: _Generic((Y), \ int * : test_int, \ default: test_int \ ) \ ) (X, Y, c) int test_double(double a, double *b, int c); int test_int(int a, int *b, int c); int test_double(double a, double *b, int c) { return 1; } int test_int(int a, int *b, int c) { return 2; } int main() { double *t = malloc(sizeof(double)); int *s = malloc(sizeof(int)); int a1 = test(3.4, t, 1); int i = 3; int a2 = test(i, s, 1); printf("%d\t", a1); printf("%d\n", a2); return 0; } 

All this works fine, but I don’t understand why these default cases in "_Generic ((Y), ..." are necessary, while I can omit it at the end of "_Generic ((X), ..." without consequences.

In fact, if I delete these two default values, I get an error message (gcc 5.4.0) saying that the 'double * type selector is not compatible with any association , while the macro extension' int a1 = test (3.4, t, 1); and the same with "int *", while the macro expansion test (i, s, 1)

Is it "default" or am I missing something? In the first case, what the hell should it be? If I have only test_double and test_int, which can be called, why should I put the default case for something that should never compile?

+6
source share
4 answers

TL DR

The selection occurs at compile time, but this does not mean that other (not selected) code is discarded. It still needs to be valid, and that means ...

If the default value is not used, and none of the type names is compatible with the type of the control expression, the program will not compile.

(Source)


It was amazing:

Without a default case for "first Y":

 #define test(X, Y, c) \ _Generic((X), \ double: _Generic((Y), \ double * : test_double \ ), \ int: _Generic((Y), \ int * : test_int, \ default: test_default \ ) \ ) (X, Y, c) 

I get this error:

prog.c: 6:30: error: selector "_Generic" of type "int *" is incompatible with any association

Note that it complains about int * , which is incompatible! What for? Take a good look at the reported line:

  int a2 = test(i, s, 1); 

X is of type int and Y type int * .

Now comes the important part: breaks occur unconditionally . Therefore, even if X is of type int , the first association for X (when it is of type double ) must be a well-formed program. Thus, with Y being int * , the following should be well formed:

 _Generic((Y), \ double * : test_double \ ), \ 

And since int * not double * , everything breaks here.


I was just looking at the standard (actually N1570) and could not find anything that actually indicates exactly this behavior. I assume that in this case it is possible to report a defect, the standard is too vague about it. I'm trying to do it now.

+4
source

_Generic , unfortunately, is unproven in the standard. Typically, the interpretation is that expressions in unselected cases should not contain constraint violations.

The simplest case:

 int main(void) { int x; _Generic(0, int: x = 5, float: x = (void)0); } 

This code gives a constraint violation in gcc because it performs a constraint check on all related expressions (not just the selected one), and x = (void)0 contains a constraint violation.


Applying this principle to your code without a default case, we see that the problem is that when a macro is created using Y as a variable declared as int *s , then one of the related expressions is _Generic(s, double * : test_double) , which is a violation of the restriction, because no case matches.

+5
source

This is due to nested _Generic choices, obviously.

The problem is that with _Generic type compatibility must be done at compile time for all possible common associations. Although only one association is selected, those that are not selected must have some compatible association.

The default association value handles each association that is incompatible with the rest of the associations for this _Generic choice.

Say you delete the default association on int: _Generic((Y), If you do, a double association will be selected, but the int association should still process the double * type, which is usually the default. In this case, there is only an association int * and it throws an error.

+1
source

This is the order of priority. In your code, two _Generic((Y) starts before _Generic((X) . They are enclosed in parentheses. The compiler works and starts for both test(3.4, t, 1) and test(i, s, 1) .

I would rewrite the code a bit.

 #define test(X, Y, c) \ _Generic((X), \ double: _Generic((Y), \ double * : test_double, \ default : test_error \ ), \ int: _Generic((Y), \ int * : test_int, \ default : test_error \ ) \ ) (X, Y, c) static void test_error(void) { /* This function should be optimised away by compiler. */ assert(0); } 
+1
source

All Articles