1 #include<stdio.h> 2 3 #define offsetof(TYPE,MEMBER) ((size_t)&((TYPE*)0)->MEMBER) 4 5 #define container_of(ptr,type,member) ({ 6 const typeof( ((type*)0)->member ) *__mptr = (ptr); 7 (type *)( (char *)__mptr - offsetof(type,member) );}) 8 9 10 #define list_entry(ptr,type,member) 11 container_of(ptr,type,member) 12 13 struct MyStruct { 14 int i_1; 15 int i_2; 16 int i_3; 17 int i_4; 18 int i_5; 19 int i_6; 20 int i_7; 21 int i_8; 22 int i_9; 23 int i_a; 24 int i_b; 25 int i_c; 26 int i_d; 27 int i_e; 28 int i_f; 29 int i_g; 30 int i_h; 31 int i_j; 32 }; 33 34 int main() 35 { 36 struct MyStruct Test = { 0,1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18}; 37 printf("Just a test: Test->i_1: %d\n",Test.i_1); 38 int *ptr = &(Test.i_2); 39 printf("Now we got i_2: %d \n",*ptr); 40 struct MyStruct *struct_ptr = container_of(ptr,struct MyStruct,i_2); 41 printf("Now we got struct\n"); 42 printf("Test.i_3 is: %d \n",struct_ptr->i_3); 43 44 return 0; 45 }
由一个struct里的member(成员)的指针得到这个struct的指针,从而可以得到这个struct的其他成员。
通过这种方法,Linux内部就不需要维护一个task_struct的双向链表了,只需要维护task_struct里面的某个成员的双向链表,效果等同于一个task_struct的双向链表。这样就可以节省空间。而通过上面的黑科技,有可以达到双向链表的效果,一举两得。
(task_struct是Linux Kernel内部用来描述一个process/thread的struct,维护一个task_struct的双向链表是因为要从一个进程得到其子进程、父进程、兄弟进程......)
可以看出其实这个黑科技之所以能实现主要是因为gcc那个 typeof 操作符......
:)
时间: 2024-10-20 05:20:15