From dc08853f66e40a9a23c7f6b344d51254e10c628e Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Thu, 5 May 2022 14:05:25 +0200 Subject: Added type-checked c_container_of() macro using typeof (C23, gcc, clang, tcc). c_unchecked_container_of() must be used by lib. --- include/stc/alt/cstr.h | 2 +- include/stc/ccommon.h | 14 ++++++++++---- include/stc/cdeq.h | 4 ++-- include/stc/clist.h | 2 +- include/stc/csmap.h | 10 +++++----- include/stc/cvec.h | 4 ++-- 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/include/stc/alt/cstr.h b/include/stc/alt/cstr.h index 3dc72178..ec7f3bba 100644 --- a/include/stc/alt/cstr.h +++ b/include/stc/alt/cstr.h @@ -34,7 +34,7 @@ #define cstr_npos (SIZE_MAX >> 1) typedef struct { size_t size, cap; char chr[1]; } cstr_priv; -#define _cstr_p(self) c_container_of((self)->str, cstr_priv, chr) +#define _cstr_p(self) c_unchecked_container_of((self)->str, cstr_priv, chr) #ifdef _i_static static cstr_priv _cstr_nullrep = {0, 0, {0}}; static const cstr cstr_null = {_cstr_nullrep.chr}; diff --git a/include/stc/ccommon.h b/include/stc/ccommon.h index 8885626c..b96cf547 100644 --- a/include/stc/ccommon.h +++ b/include/stc/ccommon.h @@ -55,9 +55,15 @@ #define c_static_assert(cond) \ typedef char c_paste(_static_assert_line_, __LINE__)[(cond) ? 1 : -1] -#define c_container_of(ptr, type, member) \ +#define c_unchecked_container_of(ptr, type, member) \ ((type *)((char *)(ptr) - offsetof(type, member))) - +#if defined _MSC_VER && __STDC_VERSION__ < 202300L +# define c_container_of(p,t,m) c_unchecked_container_of(p,t,m) +#else +# define c_container_of(ptr, type, member) \ + ((typeof(ptr))0 == (typeof(&((type *)0)->member))0, \ + ((type *)((char *)(ptr) - offsetof(type, member)))) +#endif #ifndef __cplusplus # define c_alloc(T) c_malloc(sizeof(T)) # define c_alloc_n(T, n) c_malloc(sizeof(T)*(n)) @@ -216,9 +222,9 @@ STC_INLINE char* c_strnstrn(const char *s, const char *needle, size_t slen, cons #define c_find_if(vp, C, cnt, pred) do { \ size_t index = 0; \ C##_iter _it = C##_begin(&cnt), _end = C##_end(&cnt); \ - for (; vp = _it.ref, _it.ref != _end.ref && !(pred); C##_next(&_it)) \ + for (; vp = _it.ref, vp != _end.ref && !(pred); C##_next(&_it)) \ ++index; \ - if (_it.ref == _end.ref) vp = NULL; \ + if (vp == _end.ref) vp = NULL; \ } while (0) #define c_drop(C, ...) do { \ diff --git a/include/stc/cdeq.h b/include/stc/cdeq.h index 6c92ba4a..77d2cf71 100644 --- a/include/stc/cdeq.h +++ b/include/stc/cdeq.h @@ -27,8 +27,8 @@ #include #include -struct cdeq_rep { size_t size, cap; void* base[]; }; -#define cdeq_rep_(self) c_container_of((self)->_base, struct cdeq_rep, base) +struct cdeq_rep { size_t size, cap; unsigned base[1]; }; +#define cdeq_rep_(self) c_unchecked_container_of((self)->_base, struct cdeq_rep, base) #endif // CDEQ_H_INCLUDED #ifndef _i_prefix diff --git a/include/stc/clist.h b/include/stc/clist.h index 05a7b58e..9b4560c7 100644 --- a/include/stc/clist.h +++ b/include/stc/clist.h @@ -64,7 +64,7 @@ SELF##_value value; \ } -#define clist_node_(vp) c_container_of(vp, _cx_node, value) +#define clist_node_(vp) c_unchecked_container_of(vp, _cx_node, value) _c_clist_types(clist_VOID, int); _c_clist_complete_types(clist_VOID, dummy); diff --git a/include/stc/csmap.h b/include/stc/csmap.h index 89881444..c7bf8e47 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -55,8 +55,8 @@ int main(void) { #include #include -struct csmap_rep { size_t root, disp, head, size, cap; void* nodes[]; }; -#define _csmap_rep(self) c_container_of((self)->nodes, struct csmap_rep, nodes) +struct csmap_rep { size_t root, disp, head, size, cap; unsigned nodes[1]; }; +#define _csmap_rep(self) c_unchecked_container_of((self)->nodes, struct csmap_rep, nodes) #endif // CSMAP_H_INCLUDED #ifndef _i_prefix @@ -253,11 +253,11 @@ _cx_memb(_reserve)(_cx_self* self, const size_t cap) { if (cap >= rep->size) { // second test is bogus, but supresses gcc warning: oldrep = rep->cap && rep != &_csmap_sentinel ? rep : NULL; - rep = (struct csmap_rep*) c_realloc(oldrep, sizeof(struct csmap_rep) + + rep = (struct csmap_rep*) c_realloc(oldrep, offsetof(struct csmap_rep, nodes) + (cap + 1)*sizeof(_cx_node)); if (!rep) return false; if (oldrep == NULL) - memset(rep, 0, sizeof(struct csmap_rep) + sizeof(_cx_node)); + memset(rep, 0, offsetof(struct csmap_rep, nodes) + sizeof(_cx_node)); rep->cap = cap; self->nodes = (_cx_node *) rep->nodes; } @@ -451,7 +451,7 @@ _cx_memb(_erase_r_)(_cx_node *d, i_size tn, const _cx_rawkey* rkey, int *erased) tx = tn; tn = d[tn].link[ d[tn].link[0] == 0 ]; /* move it to disposed nodes list */ - struct csmap_rep *rep = c_container_of(d, struct csmap_rep, nodes); + struct csmap_rep *rep = c_unchecked_container_of(d, struct csmap_rep, nodes); d[tx].link[1] = (i_size) rep->disp; rep->disp = tx; } diff --git a/include/stc/cvec.h b/include/stc/cvec.h index 24cf8249..83c8680d 100644 --- a/include/stc/cvec.h +++ b/include/stc/cvec.h @@ -64,8 +64,8 @@ int main() { #include #include -struct cvec_rep { size_t size, cap; void* data[]; }; -#define cvec_rep_(self) c_container_of((self)->data, struct cvec_rep, data) +struct cvec_rep { size_t size, cap; unsigned data[1]; }; +#define cvec_rep_(self) c_unchecked_container_of((self)->data, struct cvec_rep, data) #endif // CVEC_H_INCLUDED #ifndef _i_prefix -- cgit v1.2.3