原创 2007年10月14日 09:34:00

This was originally published as a side bar to an article I wrote in Linux Journal, issue 110, June 2003. I found it when someone asked about what this macro does on the #kernelnewbies irc channel and dug it up from their site. I've put it here, and updated it a bit, adding more information, as it's good to have around. I need to eventually put up all of my Linux Journal articles on my site to prevent them from ever going stale.)

What exactly does the weird Linux kernel container_of() macro do? This macro is defined as:

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

To help explain pointer mess, let us go through the steps of what it is doing. In the include/linux/i2c.h file, the to_i2c_driver() macro is defined as:

container_of(d, struct i2c_driver, driver)

and is used in code as:

i2c_drv = to_i2c_driver(drv);

where dev is a pointer to a struct device_driver.

Replacing the above code with the first macro expansion produces:

i2c_drv = container_of(drv, struct i2c_driver, driver);

Then, the next level of expansion creates:

i2c_drv = ({
const typeof( ((struct i2c_driver *)0)->driver) *__mptr = drv;
(struct i2c_driver *)( (char *)__mptr - offsetof(struct i2c_driver, driver));

To simplify this, remember that driver is a variable within the i2c_driver function. The first line of the macro sets up a pointer that points to the struct device_driver passed to the code. The second line of the macro finds the real location in memory of the struct i2c_driver that we want to access.

So with the type of the driver variable known, the macro can be reduced to:

i2c_drv = ({
const struct device driver *__mptr = drv;
(struct i2c_driver *)( (char *)__mptr - offsetof(struct i2c_driver, driver));

To show this using real numbers, say the i2c_driver structure looks like:

struct i2c_driver {
char name[32];
struct device_driver driver;

The location of the driver variable usually is 32 bytes into the structure, depending on the packing rules of the compiler at the time. For more information on how to see where variables are located in structures, see my article Writing Portable Device Drivers in the May/June 2002 issue of Embedded Linux Journal.

So, if the drv pointer is at location 0xc0101020, the __mptr variable is assigned that location in the first line of the macro. Then, the offset of the driver variable is subtracted from this address, giving us the value 0xc0101000. This would be assigned to the variable on the left side of the original assignment, i2c_drv.

Putting these values into the macro, it then is reduced to:

i2c_drv = ({
const struct device_driver *__mptr = drv;
(struct i2c_driver *)( (char *)__mptr - 0x20);

which is then evaluated at runtime by the processor as a simple subtraction on a pointer, which should be quite fast.

In order to do this kind of pointer manipulation, the code has to know the type of pointer being passed to it. The driver core only passes in the type of driver structure registered with it, so this type of manipulation is safe. This also prevents other parts of the kernel from modifying the unique fields of the structure used to control the subsystem's code.


linux内核 container_ofC语言之应用

之前在剖析内核链表的文章中就有说到这个 container_of宏展开后的应用技巧。 //offset(struct list , list);----->展开后((size_t) & (str...
  • morixinguan
  • morixinguan
  • 2016年02月04日 13:50
  • 1165

linux 内核中的container_of()如何使用

一、如何使用 我们先来分析一下container_of(ptr,type,member),这里面有ptr,type,member分别代表指针、类型、成员。看一个例子: struct test   ...
  • lz_1990
  • lz_1990
  • 2016年10月09日 15:35
  • 217


  • morixinguan
  • morixinguan
  • 2017年01月11日 14:58
  • 704


#define list_entry(ptr, type, member) ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)...
  • YuZhiHui_No1
  • YuZhiHui_No1
  • 2014年08月03日 12:09
  • 1894


在Linux内核源码文件 include/linux/kernel.h中,定义了container_of宏,源码如下:/** * container_of - cast a member of a ...
  • smstong
  • smstong
  • 2016年10月22日 10:58
  • 1140


/**  * container_of - cast a member of a structureout to the containing structure  * @ptr:       the...
  • xiezhongtian
  • xiezhongtian
  • 2014年02月20日 17:32
  • 1832


前言 驱动开发中通常为设备定义一个设备相关的设备结构体,其包含该设备的cdev 、私有数据、信号量、irq等这些信息。 驱动开发中通常将文件的私有数据private_data指向设备结构体,在...
  • u013377887
  • u013377887
  • 2017年05月31日 21:13
  • 748

container_of 的的的原理

引言:再次做H3C项目,有感触,更有成长,这篇文章很好,很容易懂。。收藏了           源地址:    ...
  • 2014年12月02日 16:34
  • 455


  • jdsnpgxj
  • jdsnpgxj
  • 2017年12月13日 16:47
  • 141

8、RIOT操作系统中 通用定时器的使用

RIOT操作系统中 通用定时器的使用         cc2538中有4个通用定时器(0-3),每个定时器有两个通道(0-1)。首先看看下面的源码。。。。。 main.c #include #in...
  • mx1252111
  • mx1252111
  • 2016年12月06日 22:45
  • 465