[ccan] [PATCH 1/3] container_of: Add container_of_or_null()

David Gibson david at gibson.dropbear.id.au
Wed Sep 10 00:22:52 EST 2014


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 <david at gibson.dropbear.id.au>
---
 ccan/container_of/container_of.h | 36 ++++++++++++++++++++++++++++++++++++
 ccan/container_of/test/run.c     |  6 +++++-
 2 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/ccan/container_of/container_of.h b/ccan/container_of/container_of.h
index 0449935..47a34d8 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 5da440a..18207f6 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);
 
-- 
1.9.3



More information about the ccan mailing list