|
|
Message-ID: <xgfp7hb5fdsxzp2htxjlcj4kfvrecl5w7jhhw3kay3iqj2kxpn@wun6pkdsgv6n>
Date: Wed, 26 Nov 2025 13:22:17 +0100
From: Alejandro Colomar <alx@...nel.org>
To: Rich Felker <dalias@...c.org>
Cc: musl@...ts.openwall.com
Subject: Re: [PATCH v2 1/1] include/string.h: Implement QChar wrappers
standardized in C23
Hi Rich,
On Tue, Nov 25, 2025 at 08:34:39PM -0500, Rich Felker wrote:
> On Tue, Nov 25, 2025 at 10:49:29PM +0100, Alejandro Colomar wrote:
[...]
> > +# 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?
Yup. I try to have 0 casts in my code. They silence several classes of
diagnostics, and allow arbitrary conversions.
For example, they could silence a bug in the prototype of strchr(3) if
it accidentally returned an int*. Admittedly, <string.h> is so stable
that it's not realistically going to have such bugs, so most of the
issues it prevents are theoretical.
In my own projects, I don't trust myself so much, so I perform all
return-value conversions through compound literals, which only allow
implicit conversions.
BTW, I've realized that there's another thing I need to fix in the
compound literals. They should be const to prevent assignment to them.
That is, my current implementation allows
strchr(s, c) = NULL;
See a test:
alx@...uan:~/tmp$ cat strchr.c
#include <stdio.h>
#include <string.h>
int
main(int argc, const char *argv[argc + 1])
{
char *p;
p = strchr(argv[0], 'u');
puts(p);
const char *cp;
cp = strchr(argv[0], 'u');
puts(cp);
&strchr(argv[0], 'u');
strchr(argv[0], 'u') = NULL;
}
alx@...uan:~/tmp$ gcc strchr.c
strchr.c: In function ‘main’:
strchr.c:17:9: error: lvalue required as unary ‘&’ operand
17 | &strchr(argv[0], 'u');
| ^
strchr.c:19:30: error: lvalue required as left operand of assignment
19 | strchr(argv[0], 'u') = NULL;
| ^
alx@...uan:~/tmp$ gcc -I /opt/local/musl/libc/qchar/include/ strchr.c
strchr.c: In function ‘main’:
strchr.c:9:11: warning: assignment discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
9 | p = strchr(argv[0], 'u');
| ^
strchr.c:17:9: error: address of register compound literal requested
17 | &strchr(argv[0], 'u');
| ^
I need to add a const qualifier to reject that:
#define strchr(s, c) ((register __QCharof(s) *const){ strchr(s, c)})
Alternatively, using a GNU extension, we can perform an lvalue
conversion of the compound literal, which solves the problems caused by
compound literals being lvalues:
#define strchr(s, c) ({(__QCharof(s) *){strchr(s, c)};})
This uses a statement expression ({...}), however. Is that okay?
It depends on which features can be required in musl's headers.
However, if you prefer it with a cast, I can change it. It's slightly
less safe, but could be okay given how stable <string.h> should be.
> Also, can't __Qcharof just be defined as something like
> typeof(1?(s):"") without any fancy _Generic machinery?
This wouldn't accept void*, and these functions should accept void*
arguments.
alx@...uan:~/tmp$ cat typeof.c
#include <stdio.h>
int
main(void)
{
const char *cc;
const void *cv;
char *c;
void *v;
_Generic(typeof(1?cc:""), const char *: 0);
_Generic(typeof(1?cv:""), const char *: 0);
_Generic(typeof(1? c:""), char *: 0);
_Generic(typeof(1? v:""), char *: 0);
}
alx@...uan:~/tmp$ gcc typeof.c
typeof.c: In function ‘main’:
typeof.c:11:18: error: ‘_Generic’ selector of type ‘const void *’ is not compatible with any association
11 | _Generic(typeof(1?cv:""), const char *: 0);
| ^~~~~~
typeof.c:13:18: error: ‘_Generic’ selector of type ‘void *’ is not compatible with any association
13 | _Generic(typeof(1? v:""), char *: 0);
| ^~~~~~
I don't know if there might be a way to write it without _Generic(3),
but I haven't found it.
Have a lovely day!
Alex
>
> Rich
--
<https://www.alejandro-colomar.es>
Use port 80 (that is, <...:80/>).
Download attachment "signature.asc" of type "application/pgp-signature" (834 bytes)
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.