diff --git a/eventrouter/internal/defs.h b/eventrouter/internal/defs.h index d042739..f2a0e55 100644 --- a/eventrouter/internal/defs.h +++ b/eventrouter/internal/defs.h @@ -4,12 +4,16 @@ #define ER_UNUSED(statement) (void)(statement); /// Returns the address of the structure containing the member. -#ifndef container_of -#define container_of(ptr, type, member) \ + +/// The "?:" conditional operator requires its second and third operands to +/// be of compatible type, so by writing "1 ? (ptr) : &((type *)0)->member" +/// instead of simply writing "(ptr)", we ensure that `ptr` actually does +/// point to a type compatible with `member` (compilation halts if it doesn't). + +#define er_container_of(ptr, type, member) \ ({ \ - const typeof(((type *)0)->member) *__mptr = (ptr); \ + void *__mptr = (1 ? (ptr) : &((type *)0)->member); \ (type *)((char *)__mptr - offsetof(type, member)); \ }) -#endif #endif /* EVENTROUTER_DEFS_H */ diff --git a/eventrouter/internal/event.h b/eventrouter/internal/event.h index 06b445f..3972a7a 100644 --- a/eventrouter/internal/event.h +++ b/eventrouter/internal/event.h @@ -89,7 +89,7 @@ extern "C" /// `a_event_p`. The developer must ensure that `a_type` is correct. This /// macro returns the surrounding struct by value instead of by reference. #define FROM_ER_EVENT(a_event_p, a_type) \ - (*container_of(a_event_p, a_type, ER_EVENT_MEMBER)) + (*er_container_of(a_event_p, a_type, ER_EVENT_MEMBER)) /// Initialize the event fields of a struct which mixes-in `ErEvent_t` /// behavior. This differs from `ErEventInit_t` in that it can be used in diff --git a/eventrouter/internal/eventrouter_baremetal.c b/eventrouter/internal/eventrouter_baremetal.c index d6f6be0..936fa61 100644 --- a/eventrouter/internal/eventrouter_baremetal.c +++ b/eventrouter/internal/eventrouter_baremetal.c @@ -226,7 +226,7 @@ ErEvent_t *ErGetEventToDeliver(void) ErList_t *node = &s_context.m_events.m_deliver_now; if (node->m_next != NULL) { - ret = container_of(node->m_next, ErEvent_t, m_next); + ret = er_container_of(node->m_next, ErEvent_t, m_next); node->m_next = node->m_next->m_next; ret->m_next.m_next = NULL; }