container_of() gcc macro

A colleague of mine approached me a few days ago with the following question – “What does container_of() do?”. He linked to the following file in the Linux kernel (we do embedded development at work),

http://lxr.free-electrons.com/source/scripts/kconfig/list.h#L18

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

At first glance, I wondered what kind of function was I looking at? It soon became clear that it wasn’t a function at all, but a macro. One of those compiler directives the kernel developers enjoy using.

The comments above the macro are answer enough, but my colleague wanted to understand how it worked. And so did I.  My first line of investigation was towards the “typeof” identifier. Wasn’t it a keyword? Turns out that I was wrong on that assumption. As far as C is concerned, “typeof” isn’t a keyword, but just another string of text. C++ on the other hand defines it as something special. Since we’re dealing with the linux kernel (usually compiled with gcc) here, further thought along that direction would be a waste of time.

I soon found out that “typeof” is a gcc macro. Here’s the documentation. In a nutshell, it’s a way to refer to the type of an expression. The examples provided with the documentation gave me a better understanding of how container_of() would work. Here is my thinking on the matter,

You provide the macro a pointer to some random element. This element is part of a larger structure – who’s address we do not know, but wish to find out. By also passing along the structure as well as identifying which element of the structure we are pointing to, container_of() returns a pointer to the parent structure.

Yeah, I found it confusing too. Took me at least 3 tries before I figured it out. So how about an example? Since we’re talking about structures, lets make one;

struct apple {
    int A;
    int AA;
    int AAA;
};

Not exactly the kind of thing you are supposed to see in a production system, but it will do for our purposes. Next we need some initialization values and a function to display its contents. So,

const struct apple apple_default = { 2 , 2 , 2 };

void show(struct apple temp)
{
    printf("A   = %d\n", temp.A);
    printf("AA  = %d\n", temp.AA);
    printf("AAA = %d\n", temp.AAA);
}

Now, let’s create an object of this structure with,

struct apple temp1 = apple_default;

And here’s where things get interesting. An assumption we make is that we only have a pointer to one of the inner variables of the structure. As a learning exercise, we’ll be working backwards. So now to get a pointer to say … the member “AA” of the structure,

int *B = &temp1.AA;

Under normal conditions this is all we’ll have. A pointer to some data which is part of a larger structure. Without direct access to the parent structure. Here is where the macro “container_of()” shows its stuff;

struct apple *B_source = container_of(B, struct apple, AAA);

Rather straightforward, won’t you say? At least, I like to think so. This example wouldn’t be complete without working source. Putting together all that’s been mentioned so far, I present to you;

#include <stdio.h>
#include <sys/types.h>
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({                      \
             const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
             (type *)( (char *)__mptr - offsetof(type,member) );})

struct apple {
    int A;
    int AA;
    int AAA;
};

const struct apple apple_default = { 2 , 2 , 2 };

void show(struct apple temp)
{
    printf("A   = %d\n", temp.A);
    printf("AA  = %d\n", temp.AA);
    printf("AAA = %d\n", temp.AAA);
}

int main(void)
{
    struct apple temp1 = apple_default;
    struct apple temp2 = apple_default;
    temp1.A     = 27;
    temp1.AA    = 44;
    temp1.AAA   = 101;
    printf("temp1:\n");
    show(temp1);
    printf("temp2:\n");
    show(temp2);

    int *B = &temp1.AA;
    printf("Value of B = %d\n", *B);

    struct apple *B_source = container_of(B, struct apple, AA);

    printf("Value of B_source:\n");
    show(*B_source);

}

I’ve tested the above with gcc in Ubuntu 12.04.3 (64bit). As an exercise for the reader, I will not post the expected output. The fun comes from doing it yourself and experimenting around. 🙂

Advertisements

2 thoughts on “container_of() gcc macro

  1. Is there some kind of bug with the container_of(ptr, type, member) when the type of member is any kind of pointer? when I change the type of AAA (above) to int * GCC reports a warning for the container_of invocation:
    warning: initialization from incompatible pointer type [enabled by default]

    • if you changed the member from (int) to (int *), then in the initialization section you would also have to change the value that gets assigned to the pointer. For example, right now in “test.c” I’m filling that value with 101. You’ll need to change that to something else. Perhaps to make another integer and use it’s address to fill in AAA ?

Comments are closed.