Eric Wong <e@xxxxxxxxx> writes: > While we cannot rely on a `__typeof__' operator being portable > to use with `offsetof'; we can calculate the pointer offset > using an existing pointer and the address of a member using > pointer arithmetic. > +/* > + * like offsetof(), but takes a pointer to type instead of the type It actually takes "a pointer to a variable of the type". I had to read the above twice to guess what is going on. > + * @ptr is subject to multiple evaluation since we can't rely on TYPEOF() > + */ > +#define OFFSETOF_VAR(ptr, member) \ > + ((uintptr_t)&(ptr)->member - (uintptr_t)(ptr)) > + This unfortunately has funny interactions with using uninitialized variables. "make CC=clang config.o" gives something like this: config.c:1944:50: error: variable 'entry' is uninitialized when used here [-Werror,-Wuninitialized] hashmap_for_each_entry(&cs->config_hash, &iter, entry, ^~~~~ ./hashmap.h:453:20: note: expanded from macro 'hashmap_for_each_entry' OFFSETOF_VAR(var, member)); \ ^~~ ./git-compat-util.h:1346:16: note: expanded from macro 'OFFSETOF_VAR' ((uintptr_t)&(ptr)->member - (uintptr_t)(ptr)) ^~~ ./hashmap.h:445:61: note: expanded from macro 'hashmap_iter_first_entry_offset' container_of_or_null_offset(hashmap_iter_first(map, iter), offset) ^~~~~~ config.c:1939:34: note: initialize the variable 'entry' to silence this warning struct config_set_element *entry; ^ = NULL Personally, I feel the workaround suggested by the compiler is just as bogus as the warning itself X-<. Casting NULL as if it were a pointer to an object of type typeof(*ptr), treating it as if it is a valid address, and doing raw address arith is just as bogus as doing the same raw address arith on an uninitialized ptr, isn't it? Anyway...