详细理解http://blog.csdn.net/jacobywu/article/details/10536467
简易理解
container_of 的定义在 Linux 内核 include/linux/kernel.h 中
- /**
- * 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) );})
其中的offsetof 的定义在 include/linux/stddef.h
- #ifdef __compiler_offsetof
- #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
- #else
- #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
- #endif
在使用过程中一般不会有什么 问题,如:
- typedef struct frame {
- int a;
- char b;
- char name[10];
- } frame_t;
- int main(int argc, char **argv)
- {
- frame_t fra, *pf;
- fra.a = 1;
- fra.b = 2;
- snprintf(fra.name, 5, "cjz%d", 1);
- pf = container_of(&fra.a, frame_t, a);
- printf("fra.a = %d, fra.b = %d, fra.name = %s\n", fra.a, fra.b, fra.name);
- return 0;
- }
但是下边的编译的时候就会有warning
- typedef struct frame {
- int a;
- char b;
- char name[10];
- } frame_t;
- int main(int argc, char **argv)
- {
- frame_t fra, *pf;
- fra.a = 1;
- fra.b = 2;
- snprintf(fra.name, 5, "cjz%d", 1);
- pf = container_of(fra.name, frame_t, name);
- printf("fra.a = %d, fra.b = %d, fra.name = %s\n", fra.a, fra.b, fra.name);
- return 0;
- }
- gcc -c -o main.o main.c
- main.c: In function ‘main’:
- main.c:29:57: warning: initialization from incompatible pointer type [enabled by default]
- gcc -Wall -I./ -o test main.o
注意红色部分,这是怎么回事呢?下面我们就来分析一下
container_of的部分展开
- container_of(fra.name, frame_t, name) 展开如下
- ({const typeof( ((frame_t *)0)->name ) *__mptr = (fra.name); \
- (frame_t *)( (char *)__mptr - offsetof(frame_t, name) );})
- 这样看来好像也没有什么 问题啊,但为什么 会有警告呢?
- 因为typeof(数组名) ,这个我个先把它称为数组名类型,而typeof( ) 中要的是一个C中定义的类型,应该为数组元素类型,所以我们这里应该传数组首元素。
- pf = container_of(fra.name, frame_t, name[0]);
- 注意红色部分与之前的不同,之前是name, 而这里是name[0]
- 改后再编译
- gcc -c -o main.o main.c
- gcc -Wall -I./ -o test main.o
- 警告就没有了