Linux Kernel Architecture

(Jacob Rumans) #1
Mauerer app03.tex V1 - 09/04/2008 6:11pm Page 1213

Appendix C: Notes on C


list_entryis implemented by means of the previously mentioned container mechanism. The following
definition ofcontainer_ofmay first appear to be somewhat confusing:


<kernel.h>
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

/**
* 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) );})

In this example, theoffsetofmacro expands as follows (some brackets have been omitted to improve
readability):


(size_t) &((struct file *)0)->f_list

The null ‘‘pointer‘‘ 0 is converted to a pointer tostruct fileby means of a typecast. This is allowed
because it does not de-reference the pointer. Consecutive execution of->and the address-of operator&
(C operator precedence!) computes the offset that must be added to a pointer to an instance of thestruct
filetype in order to get to thef_listelement. In the example, the element is directly at the beginning
of the structure, so the value 0 is returned. If the list head is at any other point in the data structure, the
function returns a positive offset. This is demonstrated in the following example:


struct test {
int a;
int b;
struct list_head *f_list;
int c;
};

long diff = (long)&((struct test*)0)->f_list;
printf("Offset: %ld\n", diff);

The program yields an offset of 8 bytes because the two integer variables, each of 4 bytes, must be skipped
to get tof_list.


If the following variant is used instead of the previous definition ofstruct test, the program returns an
offset of 0 as expected:


struct test {
struct list_head *f_list;
int a;
int b;
int c;
};
Free download pdf