Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251126013439.GV1827@brightrain.aerifal.cx>
Date: Tue, 25 Nov 2025 20:34:39 -0500
From: Rich Felker <dalias@...c.org>
To: Alejandro Colomar <alx@...nel.org>
Cc: musl@...ts.openwall.com
Subject: Re: [PATCH v2 1/1] include/string.h: Implement QChar wrappers
 standardized in C23

On Tue, Nov 25, 2025 at 10:49:29PM +0100, Alejandro Colomar wrote:
> I used compound literals instead of casts because they're less
> dangerous.  They only allow conversions that would be legal implicitly.
> 
> The register storage-class specifier is used because compound literals
> are lvalues.  register makes sure one can't take the address of them.
> That is, it rejects:
> 
> 	&strchr(s, c);
> 
> Signed-off-by: Alejandro Colomar <alx@...nel.org>
> ---
>  include/string.h | 21 +++++++++++++++++++++
>  1 file changed, 21 insertions(+)
> 
> diff --git a/include/string.h b/include/string.h
> index 83e2b946..c492698a 100644
> --- a/include/string.h
> +++ b/include/string.h
> @@ -24,6 +24,16 @@ extern "C" {
>  
>  #include <bits/alltypes.h>
>  
> +#define __QCharof(s)  typeof                                            \
> +(                                                                     \
> +	_Generic(s,                                                   \
> +		const char *:  (const char){},                        \
> +		const void *:  (const char){},                        \
> +		char *:        (char){},                              \
> +		void *:        (char){}                               \
> +	)                                                             \
> +)
> +
>  void *memcpy (void *__restrict, const void *__restrict, size_t);
>  void *memmove (void *, const void *, size_t);
>  void *memset (void *, int, size_t);
> @@ -55,6 +65,13 @@ size_t strlen (const char *);
>  
>  char *strerror (int);
>  
> +#if __STDC_VERSION__ >= 202311L
> +# define strchr(s, ...)   ((register __QCharof(s) *){ strchr(s, __VA_ARGS__)})
> +# define strrchr(s, ...)  ((register __QCharof(s) *){strrchr(s, __VA_ARGS__)})
> +# define strpbrk(s, ...)  ((register __QCharof(s) *){strpbrk(s, __VA_ARGS__)})
> +# define strstr(s, ...)   ((register __QCharof(s) *){ strstr(s, __VA_ARGS__)})
> +#endif
> +
>  #if defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
>  #include <strings.h>
>  #endif
> @@ -95,6 +112,10 @@ char *strchrnul(const char *, int);
>  char *strcasestr(const char *, const char *);
>  void *memrchr(const void *, int, size_t);
>  void *mempcpy(void *, const void *, size_t);
> +# if __STDC_VERSION__ >= 202311L
> +#  define strchrnul(s, ...)   ((register __QCharof(s) *){ strchrnul(s, __VA_ARGS__)})
> +#  define strcasestr(s, ...)  ((register __QCharof(s) *){strcasestr(s, __VA_ARGS__)})
> +# endif
>  #endif
>  
>  #ifdef __cplusplus
> -- 
> 2.51.0

Could you explain a bit about your motivations for doing it this way?
Why are compound literals needed at all instead of just a value cast?

Also, can't __Qcharof just be defined as something like
typeof(1?(s):"") without any fancy _Generic machinery?

Rich

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.