Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <2bbe4b2f-46c1-4caa-fbd9-6c8efbc0c7e5@gmail.com>
Date: Tue, 27 Oct 2020 12:38:25 +0100
From: Alejandro Colomar <colomar.6.4.3@...il.com>
To: libc-alpha@...rceware.org, libc-coord@...ts.openwall.com
Cc: libstdc++@....gnu.org, gcc@....gnu.org, linux-kernel@...r.kernel.org,
 linux-man@...r.kernel.org, jwakely@...hat.com, fweimer@...hat.com,
 ville.voutilainen@...il.com, enh@...gle.com, rusty@...tcorp.com.au
Subject: Ping(2): [PATCH v4] <sys/param.h>: Add nitems()

Ping

On 2020-09-28 21:12, 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
> 
> 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.
> 
> __nitems(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>
> ---
> 
> A few changes since v3:
> 
> - Macros don't need reserved names in their parameters,
> so I simplified those names.
> 
> - I fixed some wrong indentation levels.
> 
> - Renamed __array_len() to __nitems() for consistency.
> 
> 
>   misc/sys/param.h | 47 +++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 47 insertions(+)
> 
> diff --git a/misc/sys/param.h b/misc/sys/param.h
> index d7c319b157..08d4093961 100644
> --- a/misc/sys/param.h
> +++ b/misc/sys/param.h
> @@ -102,5 +102,52 @@
>   #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;
> +  }
> +# else /* __cplusplus < 201103L */
> +template<typename _Tp, std::size_t _Len>
> +  char
> +  (&__nitems_chararr(const _Tp(&)[_Len]))[_Len];
> +#  define nitems(arr)	(sizeof(__nitems_chararr(arr)))
> +# endif /* __cplusplus < 201103L */
> +#else /* !defined(__cplusplus) */
> +# define __nitems(arr)	(sizeof((arr)) / sizeof((arr)[0]))
> +# define nitems(arr)	(__nitems(arr) + __must_be_array(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.