On 2026-02-21 12:37, Alejandro Colomar wrote:
On 2026-02-21T17:48:31+0100, Bruno Haible wrote:
Nope, in the code I committed, 'strnul' cannot be used as a function
pointer at all.
Ahh, I misread. If you don't want to provide the function pointer,
which I think is fine (and maybe even desirable), then I would implement
it as simply as
#define strnul(s) strchr(s, '\0')
which works for both C and C++, and unless using a 10-year-old compiler,
produces optimized code.
That would be valid, yes. However, Bruno's approach allows the compiler
to not open-code strnul if it doesn't want to, which might be more
efficient in some cases. And there's another, more important difference
(see below).
Which, as you acknowledged, matches what glibc does
for const-generic macros.
It is a macro that shadows the function in function calls, but calls of
the form (strchr)(s, c) will still access the function, and of course,
function pointers will also use the function.
Yes, that's correct.
C23 says that functions like strchr are obsolescent, so arguably it's OK
if Gnulib strnul doesn't introduce an immediately-obsolescent feature,
i.e., if strnul is only a macro, not a function.
However, Gnulib strnul strays from glibc strchr in a different way.
Gnulib strnul rejects arguments of type void * (or void const *) at
compile time, whereas glibc strchr allows these arguments and treats
them like char * (or char const *). C23 implies (but does not explicitly
state) that the glibc approach is correct. Also, the sample
implementation on page 7 of
<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3020.pdf> agrees with
glibc. However, the glibc and N3020 strchr approaches are not type-safe,
e.g., they don't match how C++ works. And the utility of supporting void
* (or void const *) arguments to strchr is questionable.
What a mess....
Here are some ideas and suggestions.
1. Gnulib lib/string.in.h should contain a comment saying that its
strnul is stricter with void pointers than glibc's strchr, and why.
2. The Gnulib internal function should be renamed from gl_strchr to
__gl_strchr to make it obvious to the reader that it's private to the
implementation.
3. The Gnulib test for whether _Generic is supported is semi-duplicated
in lib/cdefs.h (copied from glibc) and in lib/string.in.h. The tests
should agree. A quick look suggests that neither approach strictly
dominates the other so a merge needs to take place.
4. Whether strchr ((void *) p) is allowed (and similarly for void const
*) should be clarified in the C standard. Must an implementation support
it? If not, is an implementation allowed to support it? That sort of
thing. My guess is that people used to C++ would say that a diagnostic
is required, but that's not what glibc does now.
5. If the standard is clarified to say that strchr ((void *) p) is not
allowed, glibc needs to be fixed.