Re: [PATCH v2] <sys/param.h>: Add nitems() and snitems() macros

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 





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@xxxxxxxxx>
> ---

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@debian:/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 */
>



[Index of Archives]     [Kernel Documentation]     [Netdev]     [Linux Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux