#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
I already know that first line is for type checking, but for the second line,
Why do it do a (char *)
casting? I find nowhere explain this.
And I do some experiment code myself, even without the casting, the result seems to be fine too.
container_of () is a macro defined in <linux/kernel.h> The syntax of the Macro is given below. container_of (ptr, type, member)
By only having a pointer on age or salary, you can retrieve the whole structure wrapping (containing) that pointer. As the name says, the container_of macro is used to find the container of the given field of a structure. The macro is defined in include/linux/kernel.h and looks like the following:
It is an utilisation of a gcc extension, the statements expressions. If you see the macro as something returning a value, then the last line would be : See the linked page for an explanation of compound statements. Here is an example : int main (int argc, char**argv) { int b; b = 5; b = ( {int a; a = b*b; a;}); printf ("b %d ", b); }
It's to get byte-level addresses for the calculation. Otherwise, pointer arithmetic would be in terms of the types being pointed at, which breaks since offsetof
computes the offset in bytes.
Casting to char *
is pretty common on the inside of low-level primitives like this, since sometimes you really need to think of memory as being an "array of bytes" and manipulate it at that level.
Consider this structure as an example:
struct demo {
int foo;
float bar;
};
now, if we did this:
struct demo test;
float *intptr = &test.bar;
we should be able to get a pointer to test
using container_of()
:
struct demo *owner = container_of(intptr, struct demo, bar);
this will expand to:
struct demo *owner = {(
const typeof( ((struct demo*)0)->bar) *__mptr = (intptr);
(struct demo*)( (char *)__mptr - offsetof(struct demo,bar) );})
So the first line declares a float
pointer __mptr
and copies the argument value to it.
The second line casts the member pointer to char *
, then subtracts the offset of bar
inside struct demo
(which will be 4, if sizeof (int)
is 4), thus getting "back up" to the address of the entire structure test
.
If the cast to char *
hadn't been there, the 4
would have been interpreted in terms of float
(since __mptr
is float *
) which would obviously back up way too far (16 bytes instead of 4, assuming float
is also 4 bytes) causing horrible breakage.
Note that the {(
syntax wrapping the expansion of container_of()
is a GCC extension; this won't work in standard C.
See this page for lots more on container_of()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With