From: Rusty Russell Date: Fri, 28 Dec 2007 12:59:11 +0000 (+1100) Subject: New variant of container_of: container_of_var, for list.h X-Git-Url: https://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=1e7eb5df1a634447ae57edf4c82a37f2d77e19ab New variant of container_of: container_of_var, for list.h --- diff --git a/container_of/container_of.h b/container_of/container_of.h index bdb23d07..1f4b18e4 100644 --- a/container_of/container_of.h +++ b/container_of/container_of.h @@ -32,4 +32,34 @@ - check_types_match(*(member_ptr), ((containing_type *)0)->member)) +/** + * container_of_var - get pointer to enclosing structure using a variable + * @member_ptr: pointer to the structure member + * @var: a pointer to a structure of same type as this member is within + * @member: the name of this member within the structure. + * + * Given a pointer to a member of a structure, this macro does pointer + * subtraction to return the pointer to the enclosing type. + * + * Example: + * struct info + * { + * int some_other_field; + * struct foo my_foo; + * }; + * + * struct info *foo_to_info(struct foo *foop) + * { + * struct info *i = container_of_var(foo, i, my_foo); + * return i; + * } + */ +#ifdef HAVE_TYPEOF +#define container_of_var(member_ptr, var, member) \ + container_of(member_ptr, typeof(*var), member) +#else +#define container_of_var(member_ptr, var, member) \ + ((void *)((char *)(member_ptr) - offsetof(containing_type, member))) +#endif + #endif /* CCAN_CONTAINER_OF_H */ diff --git a/container_of/test/compile_fail-bad-type.c b/container_of/test/compile_fail-bad-type.c index d372fa54..01dfd454 100644 --- a/container_of/test/compile_fail-bad-type.c +++ b/container_of/test/compile_fail-bad-type.c @@ -13,6 +13,7 @@ int main(int argc, char *argv[]) char *p; #ifdef FAIL + /* p is a char *, but this gives a struct foo * */ p = container_of(intp, struct foo, a); #else p = (char *)intp; diff --git a/container_of/test/compile_fail-types.c b/container_of/test/compile_fail-types.c index 33d98784..69f02daf 100644 --- a/container_of/test/compile_fail-types.c +++ b/container_of/test/compile_fail-types.c @@ -12,6 +12,7 @@ int main(int argc, char *argv[]) int *intp = &foo.a; #ifdef FAIL + /* b is a char, but intp is an int * */ foop = container_of(intp, struct foo, b); #else foop = NULL; diff --git a/container_of/test/compile_fail-var-types.c b/container_of/test/compile_fail-var-types.c new file mode 100644 index 00000000..5c776798 --- /dev/null +++ b/container_of/test/compile_fail-var-types.c @@ -0,0 +1,21 @@ +#include "container_of/container_of.h" +#include + +struct foo { + int a; + char b; +}; + +int main(int argc, char *argv[]) +{ + struct foo foo = { .a = 1, .b = 2 }, *foop; + int *intp = &foo.a; + +#ifdef FAIL + /* b is a char, but intp is an int * */ + foop = container_of_var(intp, foop, b); +#else + foop = NULL; +#endif + return intp == NULL; +} diff --git a/container_of/test/run.c b/container_of/test/run.c index ff567325..d08b06a6 100644 --- a/container_of/test/run.c +++ b/container_of/test/run.c @@ -12,8 +12,10 @@ int main(int argc, char *argv[]) int *intp = &foo.a; char *charp = &foo.b; - plan_tests(2); + plan_tests(4); ok1(container_of(intp, struct foo, a) == &foo); ok1(container_of(charp, struct foo, b) == &foo); + ok1(container_of_var(intp, &foo, a) == &foo); + ok1(container_of_var(charp, &foo, b) == &foo); return exit_status(); }