Skip to content

Instantly share code, notes, and snippets.

@Lisoph
Last active September 6, 2021 13:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Lisoph/d7ecf7fd67ed1b8c15ab876183bfe07a to your computer and use it in GitHub Desktop.
Save Lisoph/d7ecf7fd67ed1b8c15ab876183bfe07a to your computer and use it in GitHub Desktop.
CONTAINER_OF macro to downcast types more easily in C
//===--------------------~ Source ~--------------------===//
#include <stdint.h>
#ifndef offsetof
#define offsetof(type, member) ((uintptr_t)&((type*)0)->member)
#endif
#define CONTAINER_OF_CONST(member_ptr, container_ty, member_name) \
((container_ty const*) ((uintptr_t) member_ptr - offsetof(container_ty, member_name)))
#define CONTAINER_OF(member_ptr, container_ty, member_name) \
((container_ty *) ((uintptr_t) member_ptr - offsetof(container_ty, member_name)))
//===--------------------~ Usage ~--------------------===//
// Parent type
typedef struct {
float x, y;
float width, height;
} Widget;
// Child type aka. container, because it contains the parent (widget).
typedef struct {
char const *label;
Widget widget;
int times_clicked;
} ButtonWidget;
// Cast a Widget* to a ButtonWidget*
// It doesn't matter where widget is declared in the struct,
// it doesn't have to be the first member.
#define WIDGET_DOWNCAST_BUTTON(ptr) CONTAINER_OF(ptr, ButtonWidget, widget)
// Cast a ButtonWidget* to a Widget*
#define BUTTON_UPCAST_WIDGET(ptr) (&(ptr)->widget)
//===--------------------~ Example ~--------------------===//
void button_on_click(Widget *w) {
ButtonWidget *button = WIDGET_DOWNCAST_BUTTON(w);
++button->times_clicked;
}
void example() {
ButtonWidget bw = {
.label = "my button",
.widget = {
.x = .0f,
.y = .0f,
.width = 32.0f,
.height = 32.0f,
},
.times_clicked = 0,
};
button_on_click(BUTTON_UPCAST_WIDGET(&bw));
assert(bw.times_clicked == 1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment