Path: csiph.com!news.mixmin.net!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.std.c Subject: Re: Can the new generic string functions accept void* arguments? Date: Sun, 04 Jun 2023 21:37:00 -0700 Organization: None to speak of Lines: 64 Message-ID: <87fs76jzir.fsf@nosuchdomain.example.com> References: <87fs7afpcw.fsf@nosuchdomain.example.com> <87bkhyfnm7.fsf@nosuchdomain.example.com> <87r0qttw7h.fsf@bsb.me.uk> MIME-Version: 1.0 Content-Type: text/plain Injection-Info: dont-email.me; posting-host="f8790b9e901dd4e2d6ca565a2740b51b"; logging-data="284545"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+yF5UDz6Gx0B6pBrtXUIii" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) Cancel-Lock: sha1:FxutGBZmtb6OyUOVUSuIe5ngEE4= sha1:JCGB0XPe43FN8Br3L+dcqDndHMk= Xref: csiph.com comp.std.c:6494 Ben Bacarisse writes: > Keith Thompson writes: >> Keith Thompson writes: >>> The latest draft of the upcoming C23 standard is: >>> https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf >>> It introduces several type-generic functions in , replacing >>> normal functions of the same names: memchr, strchr, strpbrk, strrchr, >>> strstr. >>> >>> I'll use strchr() as an example; the same applies to the other str*() >>> generic functions (but not to memchr()). >> [...] >> >> Just after I posted the above, I thought of a potential issue with >> memchr() that just might affect real code. >> >> In C17 and earlier, memchr() has this declaration: >> >> void *memchr(const void *s, int c, size_t n); >> >> Given the implicit conversions between void* and other object pointer >> types, the first argument can be a pointer to any const object type. >> This is something that might plausibly be used in practice, unlike >> (I think) passing a void pointer to the str*() functions. >> >> It's probably impractical to fix this, since it would require >> the generic selection to cover all possible object pointer types. > > There may be a way round that... This trick converts any object pointer > to a const void * or a void * depending on the qualifiers of the object > pointer: > > #include > > #ifndef T > #define T const int > #endif > > int main(void) > { > T i; > puts(_Generic((1 ? &i : (void *)&(int){0}), > void *: "void *", > const void *: "const void *", > default: "other")); > } > > (Compile with -DT=int for example to test the other case.) > > Taking the address of (int){0} is simply a way to get a void * that is > not a null pointer constant. One could, in a macro taking pointer, just > use > > (1 ? (p) (void *)(p)) > > but some compilers will warn that the cast discards the const even > though the overall effect of the expression is to keep it. I think you're right. I'll pass it on to the editors. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Will write code for food. void Void(void) { Void(); } /* The recursive call of the void */