There are plenty of programing languages that distinguish strongly between mutable and immutable references, and that have the parametric polymorphism to let functions that can use both kinds return the same thing you passed to them, though. C will simply just never be one of them.
With that, selecting the correct function via `_Generic` should be possible (`_Generic` is a bit fiddly, but matching on `const char * ` and `char * ` should work just fine for this), and for the most part this is actually an/the intended use case for `_Generic` - it's basically the same as the type-generic math functions, more or less.
But making function signatures const-correct solves only a small part of the problem. A new API can only be used in new code, and casts can remove the constness from pointers leaving open the possibility that poorly written code will inadvertently change the const object. An attempt to change a global variable declared const will in all likelihood crash, but changing a local const can cause much more subtle bugs.
In my view, a more complete solution must include improving the detection of these types bugs in compilers and other static and even dynamic analyzers even without requiring code changes. It's not any more difficult to do that detecting out of bounds accesses. (In full generality it cannot be done just by relying on const; some other annotation is necessary to specify that a function that takes a const pointer doesn't cast the constness away and modify the object regardless.)
This, if one did:
char *strchr2(char return *restrict src, char target)
{
while(*src)
{
if (*src == target) return src;
src++;
}
}
then one version of the function could support both const and non-const usage.
BTW, I'd also like to see "register" and "return register" be usable as a qualifiers for pointer-type function parameters which would promise that the passed in pointer wouldn't "escape", or else that it could only escape through the return value (so a compiler that could see everything done with the return value wouldn't have to worry about the argument escaping).C++ solved this by overloading strchr():
const char *strchr(const char *s, int c);
char *strchr(*char *s, int c);
C of course doesn't have overloading.One solution could have been to define two functions with different names, perhaps "strchr" and "strcchr". The time to do that would have been 1989, when the original ANSI C standard was published.
I suppose a future C standard could leave strchr() as it is (necessary to avoid breaking existing code) and add two new functions.
(strchr is the most obvious, but in general most search/lookup type functions are like this...)
Add to clarify: the current prototype for strchr is
Which just drops the "const", so you might end up writing to read-only memory without any warning. Ideally there'd be something like: So the return value gets const from the input argument. Maybe this can be done with _Generic? That kinda seems like the "cannonball at sparrows" approach though :/ (Also you'd need to change the official strchr() definition...)