Reputation: 40578
Is it possible to implement the container_of macro in pure C90? I'm not sure how to do it as the Kernel implementation depends on GCC Hacks such as the typeof
operator.
I'm asking because I would like to implement a generic container in C90 similar to the Kernel's linked list. The actual container I'm thinking of is a sequenced set similar to what you might get from Boost MultiIndex.
Upvotes: 4
Views: 2083
Reputation: 14157
Yes.
The trick is replacing compound expression and typeof
used for type checking. It can be done by replacing evaluation of (ptr)
with:
(1 ? (ptr) : &((type*)0)->member)
A conditional operator always returns the first operand because its selection operand is 1. The other operand is not evaluated, therefore there is no UB due to NULL
dereferencing. Moreover, the types of operands of ?:
have to be compatible forcing type checking from a compiler.
The final macro is:
#define container_of(ptr, type, member) \
((type*)((char*)(1 ? (ptr) : &((type*)0)->member) - offsetof(type, member)))
This macro is even better than the original container_of
.
The C89 variant can be used at file scope or for initialization of static variables, while the Linux one cannot.
Upvotes: 3
Reputation: 239241
The use of typeof
in the kernel definition of container_of()
is just for compile-time type-checking - it ensures that the passed ptr
is really a pointer to the same type as member
. It can be modified to be entirely ANSI C at the cost of this type-checking:
#define container_of(ptr, type, member) ((type *)((char *)ptr - offsetof(type, member)))
(offsetof()
is in <stddef.h>
)
Upvotes: 10