Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding container_of macro in the Linux kernel

When I was browsing the Linux kernel, I found a container_of macro which is defined as follows:

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

I understand what does container_of do, but what I do not understand is the last sentence, which is

(type *)( (char *)__mptr - offsetof(type,member) );}) 

If we use the macro as follows:

container_of(dev, struct wifi_device, dev); 

The corresponding part of the last sentence would be:

(struct wifi_device *)( (char *)__mptr - offset(struct wifi_device, dev); 

which looks like doing nothing. Could anybody please fill the void here?

like image 846
jaeyong Avatar asked Apr 05 '13 11:04

jaeyong


2 Answers

Your usage example container_of(dev, struct wifi_device, dev); might be a bit misleading as you are mixing two namespaces there.

While the first dev in your example refers to the name of pointer the second dev refers to the name of a structure member.

Most probably this mix up is provoking all that headache. In fact the member parameter in your quote refers to the name given to that member in the container structure.

Taking this container 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.

That's exactly what the last line of the macro does.

like image 68
mikyra Avatar answered Sep 22 '22 15:09

mikyra


The last sentence cast:

(type *)(...) 

a pointer to a given type. The pointer is calculated as offset from a given pointer dev:

( (char *)__mptr - offsetof(type,member) ) 

When you use the cointainer_of macro, you want to retrieve the structure that contains the pointer of a given field. For example:

struct numbers {     int one;     int two;     int three; } n;  int *ptr = &n.two; struct numbers *n_ptr; n_ptr = container_of(ptr, struct numbers, two); 

You have a pointer that points in the middle of a structure (and you know that is a pointer to the filed two [the field name in the structure]), but you want to retrieve the entire structure (numbers). So, you calculate the offset of the filed two in the structure:

offsetof(type,member) 

and subtract this offset from the given pointer. The result is the pointer to the start of the structure. Finally, you cast this pointer to the structure type to have a valid variable.

like image 22
Federico Avatar answered Sep 20 '22 15:09

Federico