5

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?

Benjamin
  • 10,085
  • 19
  • 80
  • 130

4 Answers4

9

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)
user541686
  • 205,094
  • 128
  • 528
  • 886
8

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.

Eric Seppanen
  • 5,923
  • 30
  • 24
4

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."

user1284631
  • 4,446
  • 36
  • 61
0

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.

Simon Richter
  • 28,572
  • 1
  • 42
  • 64