'nitems()' calculates the length of an array in number of items.
It is safe: if a pointer is passed to the macro (or function, in C++),
the compilation is broken due to:
 - In >= C11: _Static_assert()
 - In C89, C99: Negative anonymous bitfield
 - In C++: The template requires an array

This patch also adds some other macros, which are required by 'nitems()':

__is_same_type(_a, _b):
Returns non-zero if the two input arguments are of the same type.

__is_array(_a):
Returns non-zero if the input argument is of an array type.

__must_be(_e, _msg):
Allows using _Static_assert() everywhere an expression can be used.
It evaluates '(int)0' or breaks the compilation.

__must_be_array(_a):
It evaluates to '(int)0' if the argument is of an array type.
Else, it breaks compilation.

__nitems(_a):
It implements the basic sizeof division needed to calculate
the array length.  It does what nitems(_a) did before this patch.

I'd like to put the contents of this patch in the public domain.
Feel free to do anything with it.

Signed-off-by: Alejandro Colomar <colomar.6....@gmail.com>
---

Hi,

I sent a patch like this one to glibc a few days ago.
I hope it's good for you too :-)

Disclaimer:
I don't have a FreeBSD system, so the code is not tested there.
Please test that it doesn't break anything.

Cheers,

Alex

 sys/sys/param.h | 49 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 48 insertions(+), 1 deletion(-)

diff --git a/sys/sys/param.h b/sys/sys/param.h
index d03f64f13a6..d512d21768a 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -299,7 +299,6 @@
 #ifndef howmany
 #define        howmany(x, y)   (((x)+((y)-1))/(y))
 #endif
-#define        nitems(x)       (sizeof((x)) / sizeof((x)[0]))
 #define        rounddown(x, y) (((x)/(y))*(y))
 #define        rounddown2(x, y) ((x)&(~((y)-1)))          /* if y is power of 
two */
 #define        roundup(x, y)   ((((x)+((y)-1))/(y))*(y))  /* to any y */
@@ -310,6 +309,54 @@
 #define        MIN(a,b) (((a)<(b))?(a):(b))
 #define        MAX(a,b) (((a)>(b))?(a):(b))
 
+/* Macros related to the types of variables */
+#define __is_same_type(_a, _b) (                                       \
+       __builtin_types_compatible_p(__typeof__(_a), __typeof__(_b))    \
+)
+#define __is_array(_a)         (!__is_same_type((_a), &(_a)[0]))
+
+/* Macros for embedding _Static_assert() in expressions */
+#if __STDC_VERSION__ >= 201112L
+# define __must_be(_e, _msg)   (                                       \
+       0 * (int)sizeof(                                                \
+               struct {                                                \
+                       _Static_assert((_e), _msg);                     \
+                       char_ISO_C_forbids_a_struct_with_no_members;    \
+               }                                                       \
+       )                                                               \
+)
+#else /* __STDC_VERSION__ < 201112L */
+# define __must_be(_e, _msg)   (                                       \
+       0 * (int)sizeof(                                                \
+               struct {                                                \
+                       int     : (-!(_e));                             \
+                       char _ISO_C_forbids_a_struct_with_no_members;   \
+               }                                                       \
+       )                                                               \
+)
+#endif /* __STDC_VERSION__ < 201112L */
+#define __must_be_array(_a)    __must_be(__is_array(_a), "Must be an array!")
+
+/* Macros for array sizes */
+#if defined(__cplusplus)
+# if __cplusplus >= 201103L
+template<typename _tp, std::size_t _len>
+       constexpr inline std::size_t
+       nitems(const _tp(&)[_len]) noexcept
+{
+       return _len;
+}
+# else /* __cplusplus < 201103L */
+template<typename _tp, std::size_t _len>
+       char
+       (&__nitems_chararr(const _Tp(&)[_len]))[_len];
+#  define nitems(_a)           (sizeof(__nitems_chararr(_a)))
+# endif /* __cplusplus < 201103L */
+#else /* !defined(__cplusplus) */
+# define __nitems(_a)          (sizeof((_a)) / sizeof((_a)[0]))
+# define nitems(_a)            (__nitems(_a) + __must_be_array(_a))
+#endif /* !defined(__cplusplus) */
+
 #ifdef _KERNEL
 /*
  * Basic byte order function prototypes for non-inline functions.
-- 
2.28.0

_______________________________________________
freebsd-bugs@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "freebsd-bugs-unsubscr...@freebsd.org"

Reply via email to