attractivechaos / klib

A standalone and lightweight C library
http://attractivechaos.github.io/klib/
MIT License
4.18k stars 556 forks source link

Don't pass type as named macro parameter #157

Open a-p-jo opened 2 years ago

a-p-jo commented 2 years ago

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

jmarshall commented 2 years ago

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.

a-p-jo commented 2 years ago

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

a-p-jo commented 2 years ago

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.