Take the 2-minute tour ×

While looking at Linux kernel's implementation of doubly linked circular lists, I've found following macro:


The way this works is that it returns pointer to structure given only address of one of its members:

struct blabla
    int value;
    struct list_head *list;

Thus you can get pointer to blabla (and get to "value") given only pointer to list. To my question, how would I make this as portable as possible (best case conforming to C89/C99?). Due to usage of typeof(), this is gcc only.

This is what I've got so far:

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

Is this snippet conforming to ISO standards (and thus should be able to be compiled on any conforming compiler)?

share|improve this question
statements expressions ({}) are not C standard but GNU C –  ouah Apr 22 '12 at 16:22
@ouah edited question to reflect that, thank you. –  AoeAoe Apr 22 '12 at 16:26
Note that you've lost some type checking, but I guess there's no way to keep that without typeof. –  Mat Apr 22 '12 at 16:33
add comment

3 Answers

up vote 9 down vote accepted

As Ouah commented, the ({ ... }) statement expression is a GNU extension; you won't be able to use that. Your core expression is close to what's required, but doesn't have enough parentheses:

#define container_of(ptr, type, member) \

That looks clean to me. It's only spread across two lines for SO.

share|improve this answer
Indeed, and it should be mentioned that the only reason for the Linux kernel's use of nonstandard C is improved compile-time error checking. –  R.. Apr 22 '12 at 16:59
Sounds good to me, I think I'll merge both answers into my implementation snippet. Thank you. –  AoeAoe Apr 22 '12 at 20:54
add comment

The macro is written the way it is to perfom a type check on ptr. It's possible to use a compound literal instead of the statement expression and fall back to a simple check for pointers instead of using __typeof__ if the compiler is not gcc-compatible:

#ifdef __GNUC__
#define member_type(type, member) __typeof__ (((type *)0)->member)
#define member_type(type, member) const void

#define container_of(ptr, type, member) ((type *)( \
    (char *)(member_type(type, member) *){ ptr } - offsetof(type, member)))
share|improve this answer
+1: You've done well retaining the type checking of typeof when available, and yet being correct when it isn't. –  Jonathan Leffler Apr 22 '12 at 20:59
Are these brackets fine though? {} –  AoeAoe Apr 22 '12 at 22:00
@AoeAoe: the braces are the crux of the matter - we do not cast ptr, but initialize a new value via C99 compound literal syntax; in particular, this means that only implicit conversions will be performed, which is how the type check works –  Christoph Apr 22 '12 at 23:21
@Christoph Thank you very much. –  AoeAoe Apr 23 '12 at 10:33
Just a minor suggestion: void should be changed to const void, so that if ptr is const-qualified, then the compiler won't complain about the discarding of the const qualifier. –  Alexandros Sep 29 '13 at 22:09
show 1 more comment

ISO C90 compatible version with type check. (However, caveat: two evaluations of ptr!)

#define container_of(ptr, type, member) \
   ((type *) ((char *) (ptr) - offsetof(type, member) + \
              (&((type *) 0)->member == (ptr)) * 0))

struct container {
  int dummy;
  int memb;

#include <stddef.h>
#include <stdio.h>

int main()
  struct container c;
  int *p = &c.memb;
  double *q = (double *) p;
  struct container *pc = container_of(p, struct container, memb);
  struct container *qc = container_of(q, struct container, memb);
  return 0;


$ gcc -Wall containerof.c
containerof.c: In function ‘main’:
containerof.c:20:26: warning: comparison of distinct pointer types lacks a cast
containerof.c:20:21: warning: unused variable ‘qc’
containerof.c:19:21: warning: unused variable ‘pc’

We get the distinct pointer types warning for 26, but not 25. That is our diagnostic about pointers being misused.

I first tried placing the type check into the left hand side of a comma operator, gcc complains about that having no effect, which is a nuisance. But by making it an operand, we ensure that it is used.

The * 0 is to improve the chances that that whole expression is optimized away. We don't want the compiler to be generating code which actually checks that ptr is not equal to some offset of the null pointer, which we know not to be true.

share|improve this answer
add comment

Your Answer


