Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The (char *) casting in container_of() macro in linux kernel

Tags:

c

linux

kernel

#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.

like image 478
moeCake Avatar asked Dec 06 '13 10:12

moeCake


People also ask

What is container_of () macro in Linux?

container_of () is a macro defined in <linux/kernel.h> The syntax of the Macro is given below. container_of (ptr, type, member)

How to find the container of a structure in Linux?

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:

What is a GCC macro?

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


1 Answers

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().

like image 81
unwind Avatar answered Nov 16 '22 03:11

unwind