After reading the source, I realized that I have no idea what modern, idiomatic C looks like. There are tons of uses of #define, some even in the middle of typedefs. I'm pretty sure a whole queue data structure is defined in macros in vqueue.h. Is this normal?
C does not have generics or templates so macroses are the only way to define data structures and algorithms over arbitrary types without repetition. Linux kernel uses macroses to define some data structures. Many other projects do the same.
Whether that is normal or not, it's up to developer. It's possible to use as small subset of C++ as developer wants. E.g. use only templates. But staying in C realm might be better for portability.
They first appear for kernel usage where the fact that they expanded to inline code in functions avoided creating too many stack-frames and provided optimization.
They do have the advantage of not relying on casting everything to "void *" or resort to callbacks for walking (see: TAILQ_FOREACH for instance).