Friday, August 2, 2013

container_of and offsetof in C++

I'm just putting this here for future reference

Linux uses a macro called container_of in kernel

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({                      \
      const typeof(((type *)0)->member) * __mptr = (ptr);     \
      (type *)((char *)__mptr - offsetof(type, member)); })

BSD has one

#define CONTAINING_RECORD(addr, type, field)    \
      ((type *)((vm_offset_t)(addr) - (vm_offset_t)(&((type *)0)->field)))

and so does windows

#define CONTAINING_RECORD(address, type, field) ((type *)( \
                                              (PCHAR)(address) - \
                                              (ULONG_PTR)(&((type *)0)->field)))

( These were all found at http://stackoverflow.com/questions/8240273/a-portable-way-to-calculate-pointer-to-the-whole-structure-using-pointer-to-a-fi )

I've written the linux version as a C++ template.

template<class P, class M>
size_t offsetof(const M P::*member)
{
    return (size_t) &( reinterpret_cast<P*>(0)->*member);
}

template<class P, class M>
P* container_of(M* ptr, const M P::*member)
{
    return (P*)( (char*)ptr - offsetof(member));
}

This has the added benefit of being able to 'step-into' the function, unlike a macro call.  But this also requires it to be done in C++, and not C.

In C you would call the macro        container_of( pointer, Foo, bar)
In C++ you would call the function container_of( pointer,  &Foo::bar )