This article is the continuation of the Series on the C programming tutorial and carries the discussion on C language programming and its implementation. It aims to provide easy and practical examples for understanding the C program. In our last article, we have seen the Stringizing and Token Pasting Operators in C programming.
The Linux kernel contains a very useful macro named container_of. This article is about understanding the container_of macro in Linux kernel. This article includes a simple program that illustrates how this macro is used and explains why it is so useful.
You can also read flexible array members in c, macro vs inline, and embedded interview topics.
Table of Contents
Understanding the container_of Macro in Linux kernel
Introduction
Now we will assume that we have three containers. Container-1 has gold, Container-2 has diamond and Container-3 has filled with water (Probably water is the most precious than gold and diamond). One guy comes and asks you which container contains water (Container of water). I need it desperately. You would say, Container-3 has water.
So in this example, that guy knows that one container contains water, but doesn’t know which container it is. He was using the member name (water) to know the container name or container address. So this is the use of Container_of macro in the Linux kernel.
I know the address of one member in the structure. But I don’t know the address of that structure. That structure may have many members. So we can find the address of the structure using this container_of macro in Linux Kernel.
Hope you understood this concept. If you don’t, you can understand that by using examples.
container_of()
container_of() is a macro defined in <linux/kernel.h>
The syntax of the Macro is given below.
|
Where,
It returns the address of the container structure of the member. |
We will see the example. This Example is not the Linux kernel example. This is just a C example. I’ll show you the Linux kernel example later in this post.
Container_of Macro – Example
Container_of macro will not be there in the normal C program library. This is the Linux Kernel library. So manually, I’ve added the macro to my program. Container_of macro is used to find the container structure address of the given member.
In this example, I’ve declared one structure that contains two members (mem1, mem2). I’m going to get the structure address by using the member mem2.
#include <stdio.h>
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
int main(void)
{
struct sample {
int mem1;
char mem2;
};
struct sample sample1;
printf("Address of Structure sample1 (Normal Method) = %p\n", &sample1);
printf("Address of Structure sample1 (container_of Method) = %p\n",
container_of(&sample1.mem2, struct sample, mem2));
return 0;
}
Since we know the address of the structure sample1 already. But, for your understanding of the container_of I made a very easy program. Okay, What will be the output? Both addresses should be the same or different? Let’s see the output.
Output
Address of Structure sample1 (Normal Method) = 0x7ffd0d058780 Address of Structure sample1 (container_of Method) = 0x7ffd0d058780
Yessss!!!!!. Both addresses should be the same. I hope you understood the concept of container_of macro. Do you know how that container of macro works? Start to read more.
Working of the Container_of Macro
The full expansion of this macro is shown below.
/**
* 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) );})
Did you understand anything by seeing this macro? Okay, we will go step by step. Now we will take the first line.
const typeof( ((type *)0)->member ) *__mptr = (ptr);
Here, everyone knows the use of const. So I’ll explain typeof in this line.
typeof()
Since typeof is a compiler extension, there is not really a definition for it, but in the tradition of C it would be an operator like sizeof. It takes one argument and returns the static type of the operand. Just see the below example.
Example:
#include <stdio.h>
int main(void)
{
char name[20] = "EmbeTronicX";
typeof(name) role = "Tutorial";
printf("%s %s\n", name, role);
printf("Size of name = %d, Size of role = %d\n",sizeof(name),sizeof(role));
return 0;
}
Output:
Here is the output.
EmbeTronicX Tutorial Size of name = 20, Size of role = 20
If you see the output carefully, the type of the name is assigned to the role.
Zero Point Reference
But what about the zero-pointer dereference? Well, it’s a little pointer magic to get the type of member. It won’t crash, because the expression itself will never be evaluated. All the compiler cares for is its type. The same situation occurs in case we ask back for the address. The compiler again doesn’t care for the value, it will simply add the offset of the member to the address of the structure, in this particular case 0, and return the new address.
Example:
#include <stdio.h>
int main(void)
{
struct sample {
int mem1;
char mem2;
};
printf("Offset of the member = %d\n", &((struct s*)0)->mem2);
return 0;
}
Output:
Offset of the member = 4
In this example, it returns the offset of the mem2. mem1 will occupy offset 0 to 3. So mem2 will take 4.
So, Also note that the following two definitions are equivalent:
|
|
|
|
Now let’s take the original example that we saw earlier in this post.
const typeof( ((type *)0)->member ) *__mptr = (ptr) this line creates the local constant pointer variable.
const typeof( ((type *)0)->member ) *__mptr = (ptr)—–> const char * __mptr = &sample1.mem2
Now we can take the second line which is (type *)( (char *)__mptr - offsetof(type,member) ).
offsetof()
offsetof is a macro that will return a byte offset of a member to the beginning of the structure. The macro is shown below.
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
It is even part of the standard library (available in stddef.h ).
We have already seen an example of this &((TYPE *)0)->MEMBER).
It returns an address of a member called MEMBER of a structure of type TYPE that is stored in memory from address 0 (which happens to be the offset we’re looking for).
Now we need to convert this both macro (offsetof(), container_of()) based on our original example. These macros will replace our example, like below.
container_of(&sample1.mem2, struct sample, mem2)
||
||
\/
const char * __mptr = &sample1.mem2;
struct sample * ((char*) __mptr - &((struct sample*)0)->mem2)
||
||
\/
const char* __mptr = 0x7FFD0D058784; //(Address of mem2 is 0x7FFD0D058784)
struct sample * (0x7FFD0D058784 - 4)
||
||
\/
struct sample* (0x7FFD0D058780) //This is the address of the container structure
Linux Kernel Driver Example Scenario
This is the macro of the Linux Kernel. The below snippet is an example scenario of container_of used in Linux Kernel driver.
struct foo {
spinlock_t lock;
struct workqueue_struct *wq;
struct work_struct offload;
(...)
};
static void foo_work(struct work_struct *work)
{
struct foo *foo = container_of(work, struct foo, offload);
(...)
}
static irqreturn_t foo_handler(int irq, void *arg)
{
struct foo *foo = arg;
queue_work(foo->wq, &foo->offload);
(...)
}
static int foo_probe(...)
{
struct foo *foo;
foo->wq = create_singlethread_workqueue("foo-wq");
INIT_WORK(&foo->offload, foo_work);
(...)
}
In our next article, we will see Flexible Array Member in C programming.
You can also read the below tutorials.

Embedded Software | Firmware | Linux Devic Driver | RTOS
Hi, I am a tech blogger and an Embedded Engineer. I am always eager to learn and explore tech-related concepts. And also, I wanted to share my knowledge with everyone in a more straightforward way with easy practical examples. I strongly believe that learning by doing is more powerful than just learning by reading. I love to do experiments. If you want to help or support me on my journey, consider sharing my articles, or Buy me a Coffee! Thank you for reading my blog! Happy learning!
Discover more from EmbeTronicX
Subscribe to get the latest posts sent to your email.

Very well explained! Thank you!
small doubt why are you creating local pointer and from that pointer you are subtracting the offset of member ?
since we are already having pointer, why can’t we use that pointer ?
#define container_of(ptr,type,member) (type *)( (char *)ptr – ((size_t) &((type *)0)->member) )
Thank you for the explanation
I have
some doubts Why
do we use container_of macro ?
container_of(pointer, container_type, container_field);
It is
said in the explanation 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: 1. If we want a pointer to the structure (ie container_type) we can directly assign, right?. 2. Then why the pointer of one of its field in taken to assign an address to the whole structure? 3. Please tell me the advantage of using that macro?
thank you
Hi Divin Raj,
Here we used very simple example. That’s why you have doubt like that. Below I’ll explain one of the real example.
struct foo {spinlock_t lock;
struct workqueue_struct *wq;
struct work_struct offload;
(...)
};
static void foo_work(struct work_struct *work)
{
struct foo *foo = container_of(work, struct foo, offload);
}
static irqreturn_t foo_handler(int irq, void *arg)
{
struct foo *foo = arg;
}
static int foo_probe(...)
{
struct foo *foo;
foo->wq = create_singlethread_workqueue("foo-wq"); INIT_WORK(&foo->offload, foo_work); (...)}
Code Ref : https://www.kernel.org/
If you go through the code then you will understand. In some functions we don’t pass the structure or its address. We have to pass its member of the global structure like above example. That time inside that function it will be very difficult to know how many members are there and their types. So container_of solves that. Hope you would understand.
Thanks.
Regards,
EmbeTronicX.
Thank you very much! You save my life 😀