Currently I have a macro to check a value is a type.
#define CHECK_TYPE_INLINE(val, type) \
((void)(((type)0) != (0 ? (val) : ((type)0))))
This is useful to be able to type-check macro args in some cases.
But what if I were to check against multiple types? for example, to check if it's a struct Foo *
or struct Bar *
.
Example,
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))
Is there some good way to do this?
Since this is tagged C11, you have language support for this through the _Generic keyword:
#define CHECK(x) _Generic((x), \
int : 1, \
float : 2, \
default : 3)
where 1, 2 and 3 are the things that should happen if the passed argument is of a specific type.
Link with some good examples.
To add to @Lundin's answer, this can be used with __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_, _3_, _4_, _5_, _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__)
Example use:
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))
Note, Python script used to generate _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"))