简体   繁体   中英

C11 _Generic usage

I was trying 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;
 }

This is all perfectly working, still I don't see why those default cases in "_Generic((Y), ..." are necessary while I can omit it at the end of "_Generic((X), ..." without consequences.

In fact, if I remove those two defaults I get an error (gcc 5.4.0) saying "selector of type 'double *' is not compatible with any association" while macro-expanding " int a1 = test(3.4, t, 1);" and the same thing with "int *" while macro-expanding test(i, s, 1)

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

_Generic is underspecified in the standard unfortunately. The usual interpretation seems to be that the expressions in the non-selected cases must not contain any constraint violations.

A simpler 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 constraint checking on all of the associated expressions (not just the selected one), and x = (void)0 contains a constraint violation.


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

TL;DR

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

If default is not used and none of the type-names are compatible with the type of the controlling expression, the program will not compile.

(Source)


That was a surprising one:

Without the default case for the "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 that error:

prog.c:6:30: error: '_Generic' selector of type 'int *' is not compatible with any association

Note that it complains about an int * that is not compatible! Why? Well let's look at the reported line:

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

X is of type int , and Y of type int * .

Now comes the important part: Expansions happens unconditionally . So even though X is of type int , the first association for X (when it's of type double ) has to be a well formed program. So with Y being an int * the following must be well formed:

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

And since an int * is not a double * , things break here.


I was just looking through the standard (N1570 actually) and could not find anything that actually specifies exactly this behavior , though. I guess one could report a defect in this case, the standard is too vague about this. I'm trying to do this now.

This happens because of nested _Generic selections, obviously.

The problem is that with _Generic, type compatibility must be satisfied at compile time for all possible generic associations. Even though only one association is selected, the ones that are not selected must still have some compatible association.

The association default handles every association that isn't compatible with the rest of associations for that _Generic selection.

Let's say you remove the default association on int: _Generic((Y), . If you do then the double association is selected, but the int association still must handle the double* type, which is usually done by default. In this case there is only the int* association and it outputs an error.

It is order of precedence. In Your code the two _Generic((Y) are run before _Generic((X) . They are in parentheses. The compiler is eager and run both for test(3.4, t, 1) and test(i, s, 1) .

I would rewrite the code a little.

#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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM