container_of

Usage

container_of allows data structure code to be generic across multiple data types. Data structures can be implemented without being tied to any data, and then embedded onto a container.

This binary search tree node holds no data. Instead it’s embedded onto an album.
struct bstree
{
        struct bstree* _parent;
        struct bstree* _left;
        struct bstree* _right;
};

struct album
{
        char* name;
        byte rating;
        struct bstree bst;
};

The data structure code can then manipulate structures embedded onto the container, and container_of can be used to retrieve the data.

Retrieve the data associated with a tree node.
struct bstree* node = bstree_first(tree);
struct album* album = container_of(node, struct album, bst);
printf("%s\n", album->name);

How it works

Suppose a struct album a is stored in memory at address &a. The value of a.bst will be stored at &a.bst, a certain offset bst_off from the start of the data. If we have the address of a.bst, we can figure out the address of a: &a = &a.bst - bst_off.

    &a                &a.bst = &a + bst_off
    v                 v
----+--------+--------+------------------------+----
 ...| name   | rating | bst                    |...
----+--------+--------+------------------------+----
    <-bst_off --------|

That is exactly what container_of does:

#define container_of(ptr, type, member)                       \
        ({ (type*)(((byte*)(ptr)) - offsetof(type, member)); })
((byte*)(&a.bst))

Since the offset of a struct member is given in bytes, we cast the pointer to a byte* before doing arithmetic.

offsetof(struct album, bst)

How many bytes away from the start of a struct of type struct album is the member bst stored. This is the value of bst_off.

(((byte*)(&a.bst)) - offsetof(struct album, bst))

&a.bst - bst_off gives us &a, the address of the container we wanted to find.

(struct album*)(((byte*)(&a.bst)) - offsetof(struct album, bst))

Cast the result back to the type of the container.

API

#include <container_of.h>

Defines

container_of(ptr, type, member)

Calculates the address of a container given the address of a member.

Given the address of a member embedded in a container structure, calculates the address of the container.

Parameters:
  • ptr – Pointer to the member.

  • type – Type of the container.

  • member – Name of the member.

Returns:

Address of the container.