Проверка времени компиляции для нескольких типов в C?

В настоящее время у меня есть макрос для проверки значения типа.

#define CHECK_TYPE_INLINE(val, type) \
    ((void)(((type)0) != (0 ? (val) : ((type)0))))

В некоторых случаях это полезно для проверки типов аргументов макроса.

Но что, если бы я должен был проверить несколько типов? например, чтобы проверить, является ли это struct Foo * или struct Bar *.

Пример,

static inline _insert_item(struct List *ls, void *item) { /* function body*/ }

/* type-checked wrapper */
#define insert_item(ls, item) \
    (CHECK_TYPE_ANY(item, struct Foo *, struct Bar *), \
     _insert_item(ls, item))

Есть ли хороший способ сделать это?


person ideasman42    schedule 23.09.2014    source источник
comment
Можете ли вы показать, как вы будете использовать этот макрос в примере?   -  person imreal    schedule 23.09.2014
comment
@imreal, хорошая мысль, готово   -  person ideasman42    schedule 23.09.2014


Ответы (2)


Поскольку это тег C11, у вас есть языковая поддержка для этого через ключевое слово _Generic:

#define CHECK(x) _Generic((x),  \
                   int   : 1,   \
                   float : 2,   \
                   default : 3)

где 1, 2 и 3 — это то, что должно произойти, если переданный аргумент имеет определенный тип.

Ссылка на несколько хороших примеров.

person Lundin    schedule 23.09.2014
comment
Обратите внимание, может быть полезно включить (void) перед _Generic, чтобы гарантировать, что значение никогда не используется. (при условии, что это используется только для проверки типа) - person ideasman42; 23.09.2014

Чтобы добавить к ответу @Lundin, это можно использовать с __VA_ARGS__.

/* From: http://stackoverflow.com/questions/24836793/varargs-elem-macro-for-use-with-c/24837037#24837037 */

/* -------------------------------------------------------------------- */
/* varargs macros (keep first so others can use) */
/* --- internal helpers --- */
#define _VA_NARGS_GLUE(x, y) x y
#define _VA_NARGS_RETURN_COUNT(\
    _1_, _2_, 
static inline _insert_item(struct List *ls, void *item) { /* function body*/ }

/* type-checked wrapper */
#define insert_item(ls, item) \
    (CHECK_TYPE_ANY(item, struct Foo *, struct Bar *), \
     _insert_item(ls, item))
, _VA_CHECK_TYPE_ELEM#,
for i in range(32):
    args = [(("" if c < 26 else "_") + chr(ord('a') + (c % 26))) for c in range(i + 1)]
    print("#define _VA_CHECK_TYPE_ELEM%d(var, %s) \\" % (i + 2, ", ".join(args)))
    print("    ((void)_Generic((var), %s))" % (": 0, ".join(args) + ": 0"))
, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, \ _17_, _18_, _19_, _20_, _21_, _22_, _23_, _24_, _25_, _26_, _27_, _28_, _29_, _30_, _31_, _32_, \ count, ...) count #define _VA_NARGS_EXPAND(args) _VA_NARGS_RETURN_COUNT args #define _VA_NARGS_COUNT_MAX32(...) _VA_NARGS_EXPAND((__VA_ARGS__, \ 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, \ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) #define _VA_NARGS_OVERLOAD_MACRO2(name, count) name##count #define _VA_NARGS_OVERLOAD_MACRO1(name, count) _VA_NARGS_OVERLOAD_MACRO2(name, count) #define _VA_NARGS_OVERLOAD_MACRO(name, count) _VA_NARGS_OVERLOAD_MACRO1(name, count) /* --- expose for re-use --- */ #define VA_NARGS_CALL_OVERLOAD(name, ...) \ _VA_NARGS_GLUE(_VA_NARGS_OVERLOAD_MACRO(name, _VA_NARGS_COUNT_MAX32(__VA_ARGS__)), (__VA_ARGS__)) /* -------------------------------------------------------------------- */ /* CHECK_TYPE_ANY */ #define _VA_CHECK_TYPE_ELEM2(v, a) \ ((void)_Generic((v), a: 0)) #define _VA_CHECK_TYPE_ELEM3(v, a, b) \ ((void)_Generic((v), a: 0, b: 0)) #define _VA_CHECK_TYPE_ELEM4(v, a, b, c) \ ((void)_Generic((v), a: 0, b: 0, c: 0)) #define _VA_CHECK_TYPE_ELEM5(v, a, b, c, d) \ ((void)_Generic((v), a: 0, b: 0, c: 0, d: 0)) #define _VA_CHECK_TYPE_ELEM6(v, a, b, c, d, e) \ ((void)_Generic((v), a: 0, b: 0, c: 0, d: 0, e: 0)) #define _VA_CHECK_TYPE_ELEM7(v, a, b, c, d, e, f) \ ((void)_Generic((v), a: 0, b: 0, c: 0, d: 0, e: 0, f: 0)) #define _VA_CHECK_TYPE_ELEM8(v, a, b, c, d, e, f, g) \ ((void)_Generic((v), a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0)) /* For general use */ #define CHECK_TYPE_ANY(...) VA_NARGS_CALL_OVERLOAD(_VA_CHECK_TYPE_ELEM, __VA_ARGS__)

Пример использования:

static inline _insert_item(struct List *ls, void *item) { /* function body*/ }

/* type-checked wrapper */
#define insert_item(ls, item) \
    (CHECK_TYPE_ANY(item, struct Foo *, struct Bar *), \
     _insert_item(ls, item))

Обратите внимание, скрипт Python, используемый для создания _VA_CHECK_TYPE_ELEM#

for i in range(32):
    args = [(("" if c < 26 else "_") + chr(ord('a') + (c % 26))) for c in range(i + 1)]
    print("#define _VA_CHECK_TYPE_ELEM%d(var, %s) \\" % (i + 2, ", ".join(args)))
    print("    ((void)_Generic((var), %s))" % (": 0, ".join(args) + ": 0"))
person ideasman42    schedule 23.09.2014