A tough C construct in Linux Kernel"s implementation

A tough C construct in Linux Kernel"s implementation

am 24.04.2006 07:24:25 von Arijit Das

I thought that I am very good at C until yesterday when I was browsing
thorugh the list_head data structure's implementation in Linux Kernel
2.6.10 and found that the following code:

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

is returning the "Offset of a Memeber inside a struct/class Type". I
didn't logically understand how is that happenning...:-(

I expect the outcome of &((TYPE *)0)->MEMBER to be the address of the
member 'MEMBER' of type 'TYPE'. Now, how does that address becomes
offset has totally gone out of my understanding...

Any help is highly appreciated. What am I missing...?

Thanks,
Arijit

Here is a small implemetation showing what I just said:

myhost> cat test.c
#include

#if 0
/**
* This is how it is used in Linux kernel.
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#endif

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

typedef struct list_head {
struct list_head *next, *prev;
} list_head_t;

typedef struct TypeName {
int i;
float f;
long l;
char c;
list_head_t list;
double d;
} TypeName_t;

int main()
{
int offset = offsetof(TypeName_t, list);

printf("Offset = %d\n\n", offset);
return 0;
}

myhost> gcc test.c
myhost> ./a.out
Offset = 16

myhost>
-
To unsubscribe from this list: send the line "unsubscribe linux-newbie" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.linux-learn.org/faqs

Re: A tough C construct in Linux Kernel"s implementation

am 24.04.2006 07:52:37 von Rajat Jain

>
> #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
>
> is returning the "Offset of a Memeber inside a struct/class Type". I
> didn't logically understand how is that happenning...:-(
>
> I expect the outcome of &((TYPE *)0)->MEMBER to be the address of the
> member 'MEMBER' of type 'TYPE'. Now, how does that address becomes
> offset has totally gone out of my understanding...
>

You are right ... &((TYPE *)0)->MEMBER is the address of member
"MEMBER" of type "TYPE". But consider that the (base) address of the
structure of type "TYPE" is NULL (0) as shown in above expression, and
hence the address of "MEMBER" is nothing but the offset.

An example:

Say you have:

struct student {
int roll no;
int age;
}

if you write offsetof(student, age), it converts to:

((size_t) &((student *)0)->age)

= ((size_t) &((student*)NULL)->age)

= ((size_t) 4 ) (Considering int = 4 bytes)

=4 = offset

Regards,

Rajat
-
To unsubscribe from this list: send the line "unsubscribe linux-newbie" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.linux-learn.org/faqs