klib
klib copied to clipboard
Don't pass type as named macro parameter
Instead of :
#define kvec_t(type) struct { size_t n, m; type *a; }
do :
#define kvec_t(...) struct { size_t n, m; __VA_ARGS__ *a; }
C macros are parsed in a very literal way, with no contextual awareness of {}
, etc. So while struct { int x, y; }
is a valid type, kvec_t(type)
will split it into two arguments at the first ,
and then complain about too many parameters, while kvec_t(...)
will paste the entire thing in place of __VA_ARGS__
.
The body of the #define
constructs a new type from the argument by sticking a *
on the end. This is sufficient to construct a pointer type pointing to the original type in lots of cases, but not for all C types. So in general there is no hope and you need to typedef
a name for your type. So you might as well make a typedef
(or even just add a struct tag) for your anonymous struct and pass that to kvec_t
, in which case the existing definition of the macro is fine.
@jmarshall Indeed, it is not so common to write anonymous structs by hand again and again, and even a macro expanding to it would evade this. However, as it stands, T
is not capable of reliably being every legal type. The purpose of this issue is to bring this to notice in case it was not known. I understand that it is challenging to write variadic macros like this, I myself encountered this issue when implementing a macro library and looking at kvec for ideas.
There's a further issue. ...
cannot be a function pointer, or array pointer and so on and so forth. A serious solution would require typeof(__VA_ARGS__) *
, which might even be standardised in C23
, although as yet it is a GNUC extension with similarly named counterparts in nearly all compilers but varies in behaviour of discarding or preserving qualifiers.