Question

Why do we use container_of macro ?

container_of(pointer, container_type, container_field);

It is said in the LDD that

"This macro takes a pointer to a field named container_field, within a structure of type container_type, and returns a pointer to the containing structure".

My questions are:

  • If we want a pointer to the structure (ie container_type) we can directly assign, right?
  • Then why the pointer of one of its field in taken to assign an address to the whole structure?
  • Can anybody please explain with an example the advantage of using that macro?
Was it helpful?

Solution

Let me give you an example:

struct A
{
    int some_data;
    int other_data;
};

Now let's say there is this function:

int get_some_data_from_other(int *other)
{
    struct A *a = container_of(other, struct A, other_data);
    return a->some_data;
}

As you can see, we are able to tell what is the original struct A that contains the given int *other, by knowing which field of the struct that pointer supposedly points to. The key here is that we don't have a reference to the struct itself, but just a pointer to one of its members.

This may seem absurd, but is actually useful in some very clever constructs. One very common example is the way the kernel creates linked lists. I suggest you read this post on kernelnewbies.org. Let's see a short example of it:

struct whatever
{
    /* whatever data */
    struct list_head mylist;
};

So struct whatever has some data, but it also wants to act as a node inside a linked list. What they teach you in school is to have a different struct, that contains the next/prev pointers as well as a pointer to struct whatever (or void *). That way, you have nodes through which you get to your data.

By all software engineering standards, that's actually a good thing. But software engineering standards have little regards w.r.t efficiency. See Why should I have written ZeroMQ in C, not C++ (part II).

Bottom line is, with the conventional method, you have to allocate the linked list node separately from the data node, i.e. you double the overhead of memory allocation, deallocation, fragmentation and cache misses among others. The way the Linux kernel does it is the opposite. Each data node contains a generic linked list node. The generic linked list node does not know anything about the data or how they were allocated and knows only how to connect to other linked list nodes.

So let's take a deeper look:

 +-------------------+      +---------------------+      +---------------------+
 |                   |      |                     |      |                     |
 |   WHATEVER DATA   |      |   WHATEVER DATA 2   |      |   WHATEVER DATA 3   |
 |                   |      |                     |      |                     |
 |                   |      |                     |      |                     |
 |                   |      |                     |      |                     |
 |                   |      |                     |      |                     |
 +-------------------+      +---------------------+      +---------------------+
 |                   |----->|                     |----->|                     |
 |       mylist      |      |       mylist 2      |      |       mylist 3      |
 |                   |<-----|                     |<-----|                     |
 +-------------------+      +---------------------+      +---------------------+

What you have as linked list are pointers inside struct list_head that point to other struct list_heads. Note that they don't point to struct whatever, but to the mylist inside those structs.

Say you have a node, struct whatever w. You want to find the next node. What can you do? First, you can do w.mylist.next to get a pointer to the mylist of the next node. Now you have to be able to extract the actual struct whatever containing that node. That's where container_of is used:

struct whatever w_next = container_of(w.mylist.next, struct whatever, mylist);

Finally, note that the Linux kernel has macros to traverse over all nodes of a linked list, which is more often than not what you want, so you don't actually need to use container_of directly yourself.

OTHER TIPS

Why do we use container_of macro ?

Container of macro is used to get a pointer to beginning of structure which contain element by type.

For example

struct container {
  int some_other_data;
  int this_data;
}

And a pointer int *my_ptr to the this_data member you'd use the macro to get a pointer to struct container *my_container by using:

struct container *my_container;
my_container = container_of(my_ptr, struct container, this_data);

Taking the offset of this_data to the beginning of the struct into account is essential to getting the correct pointer location.

Effectively you just have to subtract the offset of the member this_data from your pointer my_ptr to get the correct location.

Also see here which clear your doubts.

Yes, you can use write your own cast/assignment for it, but it dos have some advantages.

Efficiency - Isn't easier to just use a macro instead of declare the entire cast?

Maintenance - If everybody use the macro, you can easily change the way the pointer assignment is done, in your entire project, by just editing the macro.

Readability - What is easy do read? a explicit cast or a macro that does it for you?

Safety - You may trust that this macro works and that it runs any cast and type checking that are important, much better that your own code.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top