简体   繁体   中英

C: What does this macro mean?

How do you read the second line of this macro? What does (type *)0 mean in this context?

#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})

You're finding the type of ((type *)0)->member . It's not actually dereferencing the pointer (that would be madness, I tell you. Madness! )

It's a weirdness of C. Maybe it would make more sense if they wrote typeof(type.member) but sadly that is not allowed.

A slightly more readable version:

#define container_of(ptr, type, member) (                  \
   {                                                       \
      const typeof( ((type *)0)->member ) *__mptr = (ptr); \
      (type *)( (char *)__mptr - offsetof(type,member) );  \
   }                                                       \
)

In short, the macro defines a usable "test" that can be inserted into if and other statements. The ((type *) 0) casts a NULL reference into the type in question, and then takes the 'member' sub-component of the type. The typeof() macro will return the type associated with the member sub-"object". So it's creating a constant __mptr variable of the same type as the type.member subcomponent. For example, if we had:

typedef struct foo_s {
   int bogus;
   int bar;
} foo;

Then if invoked like this:

foo blah;  /* and initialize it of course */
int *myptr = &foo.bar;

foo *result = container_of(myptr, foo, bar);

Then the first line of the macro will turn into the following:

const int *__mptr = (myptr);

The second line of the macro then calculates the memory position of the original structure and returns the memory pointer of the structure and properly casts it to that structure, and expanded would look like:

(foo *)( (char *)__mptr - offsetof(foo, bar));

The result is that this:

foo *result = container_of(myptr, foo, bar);

allows you to take the the myptr element within the structure and extract from it the pointer to the original container.

Now, this isn't useful in the example above because you already have access to the containing structure. But pretend you didn't, because the API you're inside of wasn't passed it. This macro is a tricky way to get the parent container when you normally wouldn't have had it available.

The better thing to do, of course, is to build a better API where this hack isn't necessary. But it's useful if you c

(type *)0 is essentially NULL . The second line takes the address of the value you gave it and substracts its positions in the struct. that gives you the address of the struct

It's just like how offsetof(type, member) is defined.

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

(TYPE *)0 casts 0 to a pointer pointing to 0 of type TYPE, and ((TYPE *)0)->member points to the member of TYPE.

Actually, the second line is redundant and only for typechecking.

#define container_of(ptr, type, member) ({\ 
 (type *)( (char *)ptr - offsetof(type,member) );}) 

would have same semantics, except for type checking capability.

Look at: Rationale behind the container_of macro in linux/list.h

See also for general explanation: http://www.kroah.com/log/linux/container_of.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM