_通用来填充一些联合

问题描述 投票:0回答:1

我想使用 C11

_Generic
关键字根据静态类型填充联合,例如:

typedef union {
    double d;
    long l;
    const char*s;
    void*p;
} ty;

#define make_ty(X) _Generic((X),                        \
                            double: (ty){.d=(X)},       \
                            long: (ty){.l=(X)},         \
                            const char*: (ty){.s=(X)},  \
                            default: (ty){.p=(X)})

ty from_double(double x) { return make_ty(x); }
ty from_string(const char*s) { return make_ty(s); }
ty from_long(long l) { return make_ty(l);}

但这不能编译,例如GCC 5.3 给出(带有

gcc -std=c11 -Wall
):

u.c: In function ‘from_double’:
u.c:11:35: error: incompatible types when initializing type ‘const char *’ 
                  using type ‘double’
              const char*: (ty){.s=(X)}, \
                                   ^
u.c:14:41: note: in expansion of macro ‘make_ty’
       ty from_double(double x) { return make_ty(x); }

顺便说一句,使用

gcc -std=c99 -Wall
会产生相同的错误...

或者

_Generic
只对
tgmath.h
有用?

我以为

_Generic
会根据编译器已知的类型来选择表达式,所以无意义的
(ty){.s=(x)}
会在
from_double
中被忽略......

(如果这确实有效,我将能够根据静态的、编译器已知的参数类型“重载”

make_ty
...)

c c11
1个回答
5
投票

_Generic
的所有分支都必须是有效的代码,就像
if (1) { here; } else { there; }
之类的分支一样。要找到解决方案,您可以采取相反的方式。定义类似的函数:

inline ty from_double(double x) { return (ty){ .d = x }; }

对于所有情况,然后将宏设置为:

#define make_ty(X) _Generic((X),                     \
                            double: from_double,     \
                            long: from_long,       \
                            ...)(X)

通过

inline
的可见性,编译器实际上能够优化此类代码,并且通常不会通过调用函数指针。

© www.soinside.com 2019 - 2024. All rights reserved.