Hi Steffen,

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!  :)

> 
>  |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 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.

(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.)

[...]
> 
> 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!

:-)


Have a lovely night!
Alex

> 
> --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)

-- 
<https://www.alejandro-colomar.es>

Attachment: signature.asc
Description: PGP signature

Reply via email to