Robert S. Barnes
Robert S. Barnes

Reputation: 40578

The Linux Kernel container_of macro and generic containers in C90

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

Answers (2)

tstanisl
tstanisl

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

caf
caf

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

Related Questions