Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
768 views
in Technique[技术] by (71.8m points)

c - 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", a1);
    printf("%d
", 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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

_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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...