In Linux kernel you will find macros implemented for easy use of circular doubly linked list. One of them is list_entry as given below:
File: md@Om:/usr/src/linux-headers-2.6.28-13/include/linux/list.h
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
File: ./linux-headers-2.6.28-13-generic/include/linux/kernel.h
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr – offsetof(type,member) );})
File: ./linux-headers-2.6.28-13-generic/include/linux/stddef.h:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
I am going to explain functionality of list_entry macro. Basically list_entry returns base address of any structure by taking input as any of its member field.
e.g. you have following structure.
typedef struct student_str1 {
int rollno;
char name[20];
char foo;
char bar;
}str1;
str1 obj;
now if we pass here &obj.foo to list_entry macro, it should return us base address of struct. If you do not understand usage scenario of list_entry macro, then please browse Linux kernel source code. Here you will find only implementation details of it.
Now coming back to point, to get base address of structure we’ll have to first find out offset of corresponding member in struct & it can be achieved as follows :
&( ((str1 *) (0)) ->foo )
To get memory address of foo we’ll use (char *) ( &obj.foo). Here type cast of char * is used so that we can subtract offset of foo from its memory address which will give us base address of structure. Suppose offset of foo is 24 & memory address of foo is 0xbf8ddf6c then we will get base address of structure as 0xbf8ddf54=(0xbf8ddf6c – 24).
Now to get base address of structure you can subtract offset of foo from memory address of foo.
(char *) ( &obj.foo) - ( &( (str1 *) (0)) -> foo)
And in last you can get base address of structure str1 by
(str1 *) ( (char *) ( &obj.foo) - ( &( (str1 *) (0))-> foo) )
I know I explain things very badly. So for better understanding play with following code.
#include<stdio.h>
typedef struct student_str1 {
int rollno;
char name[20];
char foo;
char bar;
}str1;
main() {
str1 obj1;
printf ( ” \n address_rollno = %p \t offset_rollno = %u “, &obj1.rollno , (unsigned ) &(( (str1 *) (0))->rollno) );
printf ( ” \n address_foo = %p \t offset_foo = %u “, &obj1.foo , (unsigned ) &(( (str1 *)(0) )->foo ) );
printf ( ” \n address_bar = %p \t offset_bar %u” , &obj1.bar , (unsigned) &(((str1 *) (0))->bar ) ) ;
printf ( ” \n computing base address of structure by getting address of one of its members… \n\n ” ) ;
printf(“\nbase address of obj1 = % p “, (str1 *) ( (char *)(&obj1.foo) – (unsigned) &(((str1 *) (0))->foo) ) );
return 0 ;
}
I have verified above program with gcc.