|
Message-ID: <f6257d7d-1cea-b45c-a858-b80bbc1f18b1@gmail.com> Date: Fri, 25 Sep 2020 16:10:02 +0200 From: Alejandro Colomar <colomar.6.4.3@...il.com> To: libc-alpha@...rceware.org Cc: libc-coord@...ts.openwall.com, libstdc++@....gnu.org, gcc@....gnu.org, linux-kernel@...r.kernel.org, linux-man@...r.kernel.org, fweimer@...hat.com, jwakely@...hat.com, ville.voutilainen@...il.com, enh@...gle.com, rusty@...tcorp.com.au Subject: Re: [PATCH v2] <sys/param.h>: Add nitems() and snitems() macros On 2020-09-25 15:20, Alejandro Colomar wrote: > '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 > > 'snitems()' is equivalent to nitems(), > but it returns a 'ptrdiff_t' instead of a 'size_t'. > It is useful for comparison with signed integer values. > > Some BSDs already provide a macro nitems() in <sys/param.h>, > although it usually doesn't provide safety against pointers. > > This patch uses the same name for compatibility reasons, > and to be the least disruptive with existing code. > > 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(_Arr): > Returns non-zero if the input argument is of an array type. > > __must_be(_Expr, _Msg): > Allows using _Static_assert() everywhere an expression can be used. > It evaluates '(int)0' or breaks the compilation. > > __must_be_array(_Arr): > It evaluates to '(int)0' if the argument is of an array type. > Else, it breaks compilation. > > __array_len(_Arr): > It implements the basic sizeof division needed to calculate the array length. > > > P.S.: I'd like to put this patch in the public domain. > > > Signed-off-by: Alejandro Colomar <colomar.6.4.3@...il.com> > --- I patched my own system's <sys/param.h> with this, and while 'nitems()' works fine, I had to include <stddef.h> in my main.c to be able to use 'snitems()', because I didn't have 'ptrdiff_t', eventhough <sys/param.h> already includes <stddef.h>. I completely ignore the mechanisms behind system headers including other system headers. Moreover, I didn't find 'ptrdiff_t' defined in any of my systems headers I used 'user@...ian:/usr/include$ grep -rn ptrdiff_t'. Does GCC do magic? What's the problem with that? How should I fix the patch? My system: Debian bullseye/sid; x86-64; gcc 10; libc 2.31-3 Thanks, Alex > misc/sys/param.h | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 60 insertions(+) > > diff --git a/misc/sys/param.h b/misc/sys/param.h > index d7c319b157..88e95c2dba 100644 > --- a/misc/sys/param.h > +++ b/misc/sys/param.h > @@ -102,5 +102,65 @@ > #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(_Arr) (!__is_same_type((_Arr), &(_Arr)[0])) > + > +/* Macros for embedding _Static_assert() in expressions */ > +# if __STDC_VERSION__ >= 201112L > +# define __must_be(_Expr, _Msg) ( \ > + 0 * (int)sizeof( \ > + struct { \ > + _Static_assert((_Expr), _Msg); \ > + char _ISO_C_forbids_a_struct_with_no_members; \ > + } \ > + ) \ > +) > +# else > +# define __must_be(_Expr, _Msg) ( \ > + 0 * (int)sizeof( \ > + struct { \ > + int : (-!(_Expr)); \ > + char _ISO_C_forbids_a_struct_with_no_members; \ > + } \ > + ) \ > +) > +# endif > + > +# define __must_be_array(_Arr) __must_be(__is_array(_Arr), "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]) __THROW > + { > + return _Len; > + } > + > +template<typename _Tp, std::size_t _Len> > + constexpr inline std::ptrdiff_t > + snitems(const _Tp(&)[_Len]) __THROW > + { > + return _Len; > + } > + > +# else /* __cplusplus < 201103L */ > +template<typename _Tp, std::size_t _Len> > + char > + (&__nitems_chararr(const _Tp(&)[_Len]))[_Len]; > + > +# define nitems(_Arr) (sizeof(__nitems_chararr(_Arr))) > +# define snitems(_Arr) (static_cast<std::ptrdiff_t>(nitems(_Arr))) > +# endif /* __cplusplus < 201103L */ > + > +#else /* !defined(__cplusplus) */ > +# define __array_len(_Arr) (sizeof(_Arr) / sizeof((_Arr)[0])) > +# define nitems(_Arr) (__array_len(_Arr) + __must_be_array(_Arr)) > +# define snitems(_Arr) ((ptrdiff_t)nitems(_Arr)) > +#endif /* !defined(__cplusplus) */ > + > > #endif /* sys/param.h */ >
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.