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: Can the new generic string functions accept void* arguments? Date: Thu, 01 Jun 2023 21:41:03 -0700 Organization: None to speak of Lines: 76 Message-ID: <87fs7afpcw.fsf@nosuchdomain.example.com> MIME-Version: 1.0 Content-Type: text/plain Injection-Info: dont-email.me; posting-host="f8d848194142d7e3625a334b0a4a3860"; logging-data="3255063"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19Th7RMCRv9dJiN40JUr5VB" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) Cancel-Lock: sha1:7PEDMiB4FaH+cKhuLH8bgVIkkqY= sha1:v4nRBIy1APKQmNsG9U5itVpVQEA= Xref: csiph.com comp.std.c:6488 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()). The problem this solves is that calling strchr() with a const char* argument yields a non-const char* result that points into the array. For example: #include #include int main(void) { const char s[] = "hello"; char *p = strchr(s, 'h'); *p = 'J'; // Undefined behavior printf("%s\n", s); // Likely to print "Jello" } This makes it possible to obtain a non-const pointer to a const object without a pointer cast. The C23 strchr() generic function returns a char* if the first argument is a char*, or a const char* if the first argument is a const char*. The stateless search functions in this section (memchr, strchr, strpbrk, strrchr, strstr) are *generic functions*. These functions are generic in the qualification of the array to be searched and will return a result pointer to an element with the same qualification as the passed array. If the array to be searched is const-qualified, the result pointer will be to a const-qualified element. If the array to be searched is not const-qualified, the result pointer will be to an unqualified element. So far so good, and I definitely approve of this change. It does break code that calls strchr() with a const char* argument and assigns the result to a (non-const) char* object. That's IMHO a minor issue, and arguably breaking such code is part of the point of the change. (Making string literals const would be similar, but I suppose that's still a bridge too far.) But I've thought of away in which this could break some existing valid code, namely code that passes a void* or const void* argument to strchr(). Currently, since void* can be implicitly converted to char* and vice versa, such a call is valid. (I can't think of a *good* reason to write such a call, but my imagination is not unlimited.) Question: Is this a valid call in C23? (It's valid in C17.) char hello[] = "hello"; void *p = strchr((void*)hello, 'h'); An implementation of the generic strchr() will presumably use a generic selection in a macro definition. If the generic selection covers only types char* and const char*, the call will violate a constraint. If it also covers void* and const void*, the call will be valid. The current wording in N3096 suggests that only char* and const char* are covered, implying that a call with a void* or const void* argument is a constraint violation. I suggest that the C23 standard should specify whether void* arguments are valid or not. I have a slight preference for making them valid. If so, the simplest approach would be for strchr() to return a char* given a char* or void* argument, or a const char* given a const char* or const void* argument. -- 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 */