Re: Minor cleanup after adding more warnings to CFLAGS

Steffen Nurpmeso <[email protected]>
Newsgroups gmane.mail.mutt.devel
Message-ID <20260417231014.gmUM9Hd6@steffen%sdaoden.eu>
Hello Alejandro.

Thanks for your explanation.

Alejandro Colomar via Mutt-dev wrote in
 <aeF5M6eOVsGnO_Jw@devuan>:
 |On 2026-04-17T01:53:43+0200, Steffen Nurpmeso wrote:
 |> ok sorry i should not post at all .. i realized in the meantime
 |> this C23 was on the table at first long ago, by Rene Kita,
 |> already..  but
 |> 
 |> Alejandro Colomar via Mutt-dev wrote in
 |>  <aeDEw-PCa6n1P_4R@devuan>:
 |>  ..
 |>|I've implemented a patch for musl (which hasn't been merged yet).
 |>|It only needs C11 features.
 |
 |Plus typeof, which I give as granted, of course.
 |
 |> This is very (, very) cool.
 |
 |Thanks!  :)

I absolutely emphasize it.

 |>|You can have a look at it to see how that is implemented:
 |>|<https://www.openwall.com/lists/musl/2026/02/23/2>
 |> 
 |>|It's much simpler than the glibc implementation, IMO.
 |>|
 |>|I'll paste here the essentials:
 |>|
 |>| #define __QVoidptrof(p)  typeof(1?(p):(void*){0})
 |>| #define __QCharptrof(s)  typeof                               \
 |>| (                                                             \
 |>|  _Generic((__QVoidptrof(s)){0},                        \
 |>|   const void *: (const char *) 0,               \
 |>|   void *:       (char *) 0                      \
 |>|  )                                                     \
 |>| )
 |>|
 |>| #define memchr(p, ...)      ((__QVoidptrof(p)) memchr(p, __VA_ARGS__))
 |>| #define memmem(p, ...)      ((__QVoidptrof(p)) memmem(p, __VA_ARGS__))
 |>| #define memrchr(p, ...)     ((__QVoidptrof(p)) memrchr(p, __VA_ARGS__))
 |>|
 |>| #define strchr(s, ...)      ((__QCharptrof(s)) strchr(s, __VA_ARGS__))
 |>| #define strrchr(s, ...)     ((__QCharptrof(s)) strrchr(s, __VA_ARGS__))
 |>| #define strpbrk(s, ...)     ((__QCharptrof(s)) strpbrk(s, __VA_ARGS__))
 |>| #define strstr(s, ...)      ((__QCharptrof(s)) strstr(s, __VA_ARGS__))
 |>| #define strchrnul(s, ...)   ((__QCharptrof(s)) strchrnul(s, __VA_ARGS__)\
 |>| )
 |>| #define strcasestr(s, ...)  ((__QCharptrof(s)) strcasestr(s, __VA_ARGS__\
 |>| ))
 |> 
 |> That __Qvoidptr() really is magic to me.
 |> I still do not get it, and your "how" did not give any glue.
 |
 |Yup, I meant how it can be done, not really an explanation of how the
 |magic works.  I guess I should have explained it, as it's really not
 |obvious.
 |
 |The macro is
 |
 | #define __QVoidptrof(p)  typeof(1?(p):(void*){0})
 |
 |The interesting thing is the third operand to the ternary operator.
 |
 |One thing to know is that the null pointer constant is magic, and
 |different from a regular null pointer of type void*.
 |
 |Here's a relevant quote from C11 about the conditional operator:
 |
 |<https://port70.net/~nsz/c/c11/n1570.html#6.5.15p6>
 |
 | If both the second and third operands are pointers
 | or one is a null pointer constant and the other is a pointer,
 | the result type is
 | a pointer to a type
 |  qualified with all the type qualifiers
 |  of the types referenced by both operands.
 | Furthermore,
 | if both operands are pointers to compatible types
 | or to differently qualified versions of compatible types,
 | the result type is
 | a pointer to
 |  an appropriately qualified version
 |  of the composite type;
 | if one operand is a null pointer constant,
 | the result has the type
 |  of the other operand;
 | otherwise,
 | one operand is a pointer to void or a qualified version of void,
 | in which case the result type is
 |  a pointer to an appropriately qualified version
 |  of void.

This, to my shame maybe even, is already in ISO C99.

 |This means that
 |
 | const    int  *p;
 | volatile int  *q;
 |
 | typeof(1 ? p : q)            x;  // const volatile int  *
 | typeof(1 ? p : NULL)         y;  // const          int  *
 | typeof(1 ? p : (void *){0})  z;  // const          void *
 |
 |In the case of x, the clause 'Furthermore, ...' applies.
 |In the case of y, the clause 'if one operand is a null pointer
 |constant, ...' applies.
 |In the case of z, since (void*){0} is not a null pointer constant, but
 |it is a pointer to void, the last clause applies, and thus we get an
 |appropriately qualified version of void.
 |
 |This can be shown with the following program:
 |
 | alx@devuan:~/tmp$ cat t.c 
 | #include <stddef.h>
 |
 | int
 | main(void)
 | {
 |  const    int  *p;
 |  volatile int  *q;
 |
 |  _Generic(typeof(1 ? p : q),           const volatile int  *: 0);
 |  _Generic(typeof(1 ? p : NULL),        const          int  *: 0);
 |  _Generic(typeof(1 ? p : (void *){0}), const          void *: 0);
 |}
 | alx@devuan:~/tmp$ gcc -Wall -Wextra -Wno-unused t.c 
 | alx@devuan:~/tmp$ 
 |
 |About why the compound literal (void *){0} is not a null pointer
 |constant, it's because the null pointer constants are very limited.
 |<https://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p3>
 |
 | An integer constant expression with the value 0,
 | or such an expression cast to type void *,
 | is called a null pointer constant.
 |
 |Since a compound literal is none of that, it can't be a null pointer
 |constant, which gives us the interesting properties we get here.

Very, very smart, to the point.  I myself would be massively
afraid of inventing something like this (in case i could/can) in
practice because of compatibility issues.  (For example, i had
major distress when gcc 3.4.2 came out with a hatred against
unnamed unions, but the necessity to be compatible with it,
quickly.  Or clang 5.0.1 which did not find superclass fields (of
*some* classes) unless they were explicitly mentioned via this->.
And many miscompilation problems.  You know all that.)

 |(BTW, an integer constant expression with the value 0 will eventually
 | stop being a null pointer constant.  GCC has added
 | -Wzero-as-null-pointer-constant in C mode recently, and some
 | C Committee members --including myself, and some GCC contributors-- are
 | planning the removal in the standard in a way that will have a
 | relatively smooth transition.  Then, the only null pointer constant
 | will be (void*)0, and of course the horrible nullptr, but we better
 | act as if that never existed.)

This is very much interesting (surely nitpicker etc will not fit
your picture), especially given that C++ has 0l as NULL (except
that "__cplusplus + 0 >= 201103L" has nullptr as far as
i discovered).

One thing i always "hated".  Unfortunately C++ is not simply an
extension of C, with both "variants" taking painstaking efforts
in that direction.

 |[...]
 |> 
 |> But that __Qvoidptr() totally escapes me.
 |> Ie decay (Joy Division is greeting) back and forth, i must specify
 |> a compatible pointer type, and no matter whether i say
 |>   typeof(true ? x : y)
 |> or
 |>   typeof(false ? x : y)
 |> or the order of x and y, i will always get a "void [const]*".
 |> 
 |> I mean, "all pointer types implicitly convert to void*".
 |> But it is total magic!
 |
 |:-)

I will not forget it.  Thanks for your explanation!

 |Have a lovely night!

You too.

--steffen
|
|Der Kragenbaer,                The moon bear,
|der holt sich munter           he cheerfully and one by one
|einen nach dem anderen runter  wa.ks himself off
|(By Robert Gernhardt)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.