1

I came across piece of code that uses container_of.

typedef struct api_1 api_2;

typedef void (*api_set)(api_2 *api, int a);

struct api_1{
    api_set set;
};

typedef struct{
    api_2 api;
    int value;
} api_p_t;

void set(api_2 *api, int a){
    api_p_t *priv_api = container_of(api, api_p_t, api);
    priv_api->value = a;
}

Please explain me, why "container_of(api, api_p_t, api)" uses parameter "api" twice? Is it some kind of polymorphic behaviour?

  • 4
    Unrelated: `typedef struct api_1 api_2;` shouldn't pass through code review. – Ted Lyngmo Jun 09 '22 at 17:14
  • The first one is a pointer to a member whose container struct you are looking for. The second is the member name that the pointer should be corresponding to. That is "Find a container that is containing a member named "api"(3rd argument) which a pointer "api" (1st argument) is pointing to". – Eugene Sh. Jun 09 '22 at 17:25
  • @TedLyngmo Do you mean it shouldn't pass code review because `struct api_1` is incomplete at that point, or because the combination of identifiers `api_1` and `api_2` is potentially misleading? – Ian Abbott Jun 09 '22 at 17:45
  • 1
    @IanAbbott The misleading part. I have no problem with `typedef`ining before actually defining the type. It's perfectly ok. – Ted Lyngmo Jun 09 '22 at 17:46

1 Answers1

3

Apparently this is a Linux Kernel macro:

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

So, the first api is the api_2 pointer named api that is passed in as a parameter to the function. The second api is the api_p_t member named api.

api_p_t *priv_api = ({
    const typeof(((api_p_t *)0)->api) * __mptr = (api);
    (api_p_t*)((char *)__mptr - offsetof(api_p_t, api));
});
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108