From: David Gibson Date: Tue, 9 Sep 2014 14:22:52 +0000 (+1000) Subject: container_of: Add container_of_or_null() X-Git-Url: https://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=7ec5b8e06b2fd5fa98b1fcde1158c286d2d429d8 container_of: Add container_of_or_null() It's quite common to have a pointer which could be either a pointer to a structure member, or NULL. This needs special casing with container_of(), or it will convert NULL into something strange. This patch adds container_of_or_null(), which will return NULL if passed (an appropriately typed) NULL, or the containining structure as container_of() otherwise. Signed-off-by: David Gibson Signed-off-by: Rusty Russell --- diff --git a/ccan/container_of/container_of.h b/ccan/container_of/container_of.h index 04499350..47a34d85 100644 --- a/ccan/container_of/container_of.h +++ b/ccan/container_of/container_of.h @@ -36,6 +36,42 @@ - container_off(containing_type, member)) \ + check_types_match(*(member_ptr), ((containing_type *)0)->member)) + +/** + * container_of_or_null - get pointer to enclosing structure, or NULL + * @member_ptr: pointer to the structure member + * @containing_type: the type 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, unless it + * is given NULL, in which case it also returns NULL. + * + * Example: + * struct foo { + * int fielda, fieldb; + * // ... + * }; + * struct info { + * int some_other_field; + * struct foo my_foo; + * }; + * + * static struct info *foo_to_info_allowing_null(struct foo *foo) + * { + * return container_of_or_null(foo, struct info, my_foo); + * } + */ +static inline char *container_of_or_null_(void *member_ptr, size_t offset) +{ + return member_ptr ? (char *)member_ptr - offset : NULL; +} +#define container_of_or_null(member_ptr, containing_type, member) \ + ((containing_type *) \ + container_of_or_null_(member_ptr, \ + container_off(containing_type, member)) \ + + check_types_match(*(member_ptr), ((containing_type *)0)->member)) + /** * container_off - get offset to enclosing structure * @containing_type: the type this member is within diff --git a/ccan/container_of/test/run.c b/ccan/container_of/test/run.c index 5da440a1..18207f60 100644 --- a/ccan/container_of/test/run.c +++ b/ccan/container_of/test/run.c @@ -12,9 +12,13 @@ int main(int argc, char *argv[]) int *intp = &foo.a; char *charp = &foo.b; - plan_tests(8); + plan_tests(12); ok1(container_of(intp, struct foo, a) == &foo); ok1(container_of(charp, struct foo, b) == &foo); + ok1(container_of_or_null(intp, struct foo, a) == &foo); + ok1(container_of_or_null(charp, struct foo, b) == &foo); + ok1(container_of_or_null((int *)NULL, struct foo, a) == NULL); + ok1(container_of_or_null((char *)NULL, struct foo, b) == NULL); ok1(container_of_var(intp, &foo, a) == &foo); ok1(container_of_var(charp, &foo, b) == &foo);