Tuesday, September 23, 2008

Getting from a structure member pointer to the structure pointer

This is typically something that is required in system software - where you have a pointer to a member of a structure, and you want to get to the base address of the structure itself. Generally speaking this should be easy enough - since you know the offset of the member, you simply subtract the sizes of every member that comes before the member whose pointer we have, and we should have a pointer to the base.

Generally speaking, there are more elegant ways of doing this. One way I have seen is this:

Consider a structure like this:

struct mystruct {
member *a;
another_member b;
something *c;
...
};

So, if you have a pointer to c, to get a pointer to mystruct, you could do this:

mystruct *s = (mystruct *)(( (byte *)c - (byte *)((mystruct *)0)->c)

What this is doing is casting the address 0 to the type mystruct. Then, if you are pointing to the "c" member, that gives you the actual relative offset of "c" in the structure. All that remains is to subtract this offset from "c" itself, in order to get a pointer to the containing structure.

Linux kernel does something similar - the macro container_of provides this functionality:


#define offsetof(TYPE, MEMBER)
((size_t) &((TYPE *)0)->MEMBER)
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})

It does the same thing if you ignore all the casting. It first gets a pointer to the member of a 0-based structure, and then subtracts the offset of the member from this address to get the base.

No comments: