Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I don't see this as particularly monstrous - it's reasonably succinct, and in this case a macro implementation does the job just as well as a built-in linked list would, and with much more flexibility.

    #define VTAILQ_INSERT_BEFORE(listelm, elm, field) do {              \
        (elm)->field.vtqe_prev = (listelm)->field.vtqe_prev;            \
        VTAILQ_NEXT((elm), field) = (listelm);                          \
        *(listelm)->field.vtqe_prev = (elm);                            \
        (listelm)->field.vtqe_prev = &VTAILQ_NEXT((elm), field);        \
    } while (0)
(I don't understand why it uses VTAILQ_NEXT((elm), field) instead of what it expands to, (elm)->field.vtqe_next - that would make it more obvious what's going on by paralleling the use of vtqe_prev - but that's the fault of the macro implementation.)


There are many things horrible about it. Its arguments are evaluated many times which is different than what you would expect. The fact that you have to pass field is just plain clumsy.

C could benefit tremendously from a parameterized type mechanism.


> Its arguments are evaluated many times which is different than what you would expect.

True - I would like to see the GCC extension that allows this to be done safely standardized, or improved.

> The fact that you have to pass field is just plain clumsy.

Sort of. I think the C trick of having linked list pointers inside the struct rather than the usual external wrapper is quite nice: it has good performance (especially in cases with multiple lists, to the extent that Boost has Boost.Intrusive even though it's really gross in C++), and explicitly codifying "struct A is a member of exactly one A-list" makes things feel simpler to me. You could have some kind of magic object in the list head that defines which member field it uses, but I don't know if that's worth the downside of the implementation no longer being trivial (and thus easy to understand).

I mean, there are lots of generally ugly points to C macros, but I have yet to see a better option for this kind of stuff that doesn't sacrifice either performance or simplicity - although the macro language itself could certainly be vastly improved.


Can anyone explain why this needs to be a macro? What does this get you over a plain function?


The idiomatic way you'd express a generic tailq in C with functions is with void-stars, which cost 4-8 bytes and incur the costs of indirecting through another memory address and, probably, of allocating lots of fiddly little structs at random times.

The macro version expresses the same generalized logic but embeds the link pointers in the structure you're queueing.


Thanks! Helpful as always.


The "field" argument cannot be passed as an argument to a normal function in C. FWIW, you could pass it as an argument in C++ (which supports pointers to members), but in C++ there are numerous better ways of implementing this.


It's intended to be used with lists with different payloads, all "inheriting" fields from a standard list structure (usually another macro expansion).




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: