Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <ytmmqdtkpsdbxvnzziomgmur34ejms7pdesma5ogy2nvlcpu7h@lq3qkschclcd>
Date: Thu, 27 Nov 2025 16:59:17 +0100
From: Alejandro Colomar <alx@...nel.org>
To: Markus Wichmann <nullplan@....net>
Cc: musl@...ts.openwall.com
Subject: Re: [PATCH v2 1/1] include/string.h: Implement QChar wrappers
 standardized in C23

Hi Markus,

On Thu, Nov 27, 2025 at 04:01:56PM +0100, Markus Wichmann wrote:
> Am Wed, Nov 26, 2025 at 04:18:25PM -0500 schrieb Rich Felker:
> > Hmm, maybe it doesn't work. It looks like only exactly (void *)0 is a
> > null pointer constant. A cast to a qualified void pointer type isn't
> > one. I'm not sure if it's fixable.
> > 
> > Rich
> 
> There really is no expression that turns void* into char*, or at least
> not that I could find. But it is possible to simplify the generic
> expression Alejandro is using:
> 
> #define _QChar(s) typeof(_Generic(1?(s):(void *)"", void *: (char *)0, const void *: (const char *)0))
> #define strstr(s, c) ((_QChar(s))strstr(s, c))

Interesting.  I think this is the key to implement __QVoid().  I was
scratching my head, but couldn't come up with a way.  I've split your
macro into two:

	alx@...uan:~/tmp$ cat typeof.c 
	#include <stddef.h>

	#define QVoidptrof(p)  typeof(1?(p):(void *)"")
	#define QCharptrof(s)  typeof(_Generic(QVoidptrof(s), void *: (char *)0, const void *: (const char *)0))

	int
	main(void)
	{
		const char *cc;
		const void *cv;
		const int  *ci;
		char *c;
		void *v;
		int  *i;

		_Generic(QCharptrof(  cc), const char *: 0);
		_Generic(QCharptrof(  cv), const char *: 0);
		_Generic(QCharptrof(   c),       char *: 0);
		_Generic(QCharptrof(   v),       char *: 0);
		_Generic(QCharptrof(NULL),       char *: 0);

		_Generic(QVoidptrof(  cc), const void *: 0);
		_Generic(QVoidptrof(  cv), const void *: 0);
		_Generic(QVoidptrof(  ci), const void *: 0);
		_Generic(QVoidptrof(   c),       void *: 0);
		_Generic(QVoidptrof(   v),       void *: 0);
		_Generic(QVoidptrof(   i),       void *: 0);
		_Generic(QVoidptrof(NULL),       void *: 0);
	}

	alx@...uan:~/tmp$ gcc typeof.c 
	alx@...uan:~/tmp$ 

I'll send a revision of the patch using this to also wrap the mem*()
functions.  Thanks!  I'll add a Co-authored-by tag, if you agree.

> Feel free to reformat as you like.
> 
> The controlling expression of the generic is compatible with all pointer
> types, and always becomes a void* or const void*. This means it already
> has the correct type for the mem* functions and bsearch(), once you
> start looking at those. For the str* functions, the only way I see to
> get from those to char* is the generic expression.

Yup, thanks!

> The idea is to use an expression to query the const qualifier only.
> According to the rules for conditional operators, I will get an equally
> qualified void pointer only if the third expression is a non-null void
> pointer (I would get the original type of s if it were a null pointer
> constant). The simplest non-null pointer I can find is a string
> literal.
> 
> I think it is better to let the const correctness macro only handle the
> return value, because it leads to better error messages. With
> Alejandro's current attempt, something like
> 
> int *p;
> strstr(p, "");
> 
> will lead to an error message about no case existing for int* in the
> generic expression, whereas my solution will leave the original error
> message the compiler would generate from initializing a const char *
> from an int * in place.

Sounds good.  Thanks!


Have a lovely day!
Alex

> 
> Ciao,
> Markus

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