I know what the macro does.
In many kernel level codes, it is often used to traverse linked-list.
I want to find other useful cases.
When do you use container_of or CONTAINING_RECORD macro?
When is the macro extremely useful?
I know what the macro does.
In many kernel level codes, it is often used to traverse linked-list.
I want to find other useful cases.
When do you use container_of or CONTAINING_RECORD macro?
When is the macro extremely useful?
It's a way to go around the fact that C doesn't have generics or templates.
You want a generic linked list, so you just put the pointers inside the node itself (so that you can abstract away the management of the structure itself), then use CONTAINING_RECORD
to find the rest of the data in your own code, e.g.:
struct Node { struct Node *prev, *next; }
//Now you can define functions that operate on a generic struct Node*
struct Item
{
int myData;
struct Node node;
}
Now, given a struct Node
, you can find its Item
by saying:
CONTAINING_RECORD(ptr, Item, node)
container_of
allows you to simplify your data structures by omitting pointers to parent structures.
It's used within the linked list implementation so that the list node can be an element of any structure, and anyone can find the parent structure without carrying around an explicit pointer.
Another example is struct work_struct
. A workqueue work function receives a work_struct as an argument, and it used to have a generic "data" payload. This data value was removed, making the structure smaller, as the work function can call container_of
to find its parent structure.
For the future searche(r)s: this is the best explanation that I found so far:
http://psomas.wordpress.com/2009/07/01/weird-kernel-macros-container_of/
Basically (quote):
"Now we can understand(at least partially) what the macro does. It declares a pointer to the member of the struct that ptr
points to, and assigns ptr to it. Now __mptr
points to the same address as ptr
. Then it gets the offset of that member
within the struct
, and subtracts it from the actual address of the member of the struct ‘instance’(ie __mptr)
. The (char *)__mptr
cast is necessary, so that ‘pointer arithmetic’ will work as intended, ie subtract from __mptr
exactly the (size_t)
bytes that offsetof
‘returns’."
and, also, two other significant hints (quote):
"At this point, I really can’t understand why we couldn’t use the ptr pointer directly. We could ommit the first line, and the macro could be
#define container_of(ptr, type, member) (type *)( (char *)(ptr) - offsetof(type,member) )
ptr
is used only once — we don’t need to worry about side effects.
Maybe it’s just good coding practice."
and, the later edit of the original post (quoted):
"Apparently, the first line is there for ‘type checking’. It ensures that type
has a member called member
(however this is done by offsetof
macro too, I think), and if ptr
isn’t a pointer to the correct type (the type of the member
), the compiler will print a warning, which can be useful for debuging."
It adjusts a pointer to a member of a struct to a pointer to the containing struct; this is used in various ways in the kernel, the most common could be described as a downcast with a static offset where the outer structure is derived (by inclusion) from the inner, and the caller invokes a method on the inner object, which is then dispatched to a method on the outer object.
Well, that, without OO support from the compiler.