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>
signature.asc
Description: PGP signature
