Subject: Re: __UNCONST(a)
To: NetBSD Userlevel Technical Discussion List <tech-userlevel@NetBSD.org>
From: Andrew Brown <firstname.lastname@example.org>
Date: 07/06/2004 01:49:33
On Mon, Jul 05, 2004 at 07:50:41PM -0400, Greg A. Woods wrote:
>[ On Sunday, July 4, 2004 at 16:38:46 (+0100), David Laight wrote: ]
>> Subject: Re: __UNCONST(a)
>> This is one reason why I dislike using casts to remove compiler/lint
>> warnings - it can hide a real error.
>Personally I'd rather see the compiler emit the warning when compiling
>the likes of strstr() and to find a big fat human-readable comment with
>strstr.c that explains why the compiler will emit a warning when
>compiling that code.
that sounds nice, but there's currently no way (that i know of) to
tell gcc "yes, you're going to emit a warning for this, but please
ignore it even if -Werror is set, m'kay?"
>I recently had the "pleasure" of porting some code to a recent version
>of the MIPS-Pro compiler (on SGI IRIX 6.x). They've got some fairly
>powerful facilities for controlling warning levels using lint-style
>comments, and warnings that the kind that "-Werror" would turn into
>non-zero exit codes can be reduced to what they call "remarks" which are
>still emitted by the compiler but which do not cause a non-zero exit
>code. However I think doing that kind of thing in GCC would require a
>heck of a lot more organization and control than seems to be possible in
>most open source projects in order to assign identifiers or index
>numbers for each and every type of error, and so on, and to make sure
>they stay consistent across platforms and across releases.
>It's also why given what I know now I would redesign the strstr() API,
>for example, thusly:
> strstr(const char *big, const char *little, const char **result);
>so that it would be the caller's responsibility to either pass the
>address of a "const char *" variable through "result" or else apply a
>cast to add the "const" qualifier at that point; instead of forcing the
>implementation to create a possible problem where "const" is invisibly
>lost through pointer aliasing within the system library.
[i'm going to refer to strchr() instead of strstr() because it's a tad
simpler while it still belongs to the same "problem domain"]
the "problem" is that (a) strchr() needs to be able to operate over
both "const" and "non-const" char* arguments. that means there are
cases where (1) the space addressed by the first argument is known to
the caller to be writeable and cases where (2) it is not known to be
(there's also the case where it's known not to be, but that's
effectively uninteresting). oh, (b) strchr() never modifies anything
addressed by its first argument anyway, so the use of the const
keyword makes even more sense.
the problem is further compounded where the case 1 caller wants to
change something in the string, eg (in brief):
if ((p = strchr(foo, ':')) != NULL)
*p++ = '\0';
now clearly this use case needs to be supported, so clearly the return
value of strchr() must not be const. the caller is simply expected to
know if it thinks the space its searching with strchr() is writeable
or not, even if strchr() doesn't need to know.
your solution above doesn't address this, and actually makes it worse.
now i have this:
if (strchr(foo, ':', &p) == 0)
*p++ = '\0';
if p is not a const char *, the compiler will whine about line 1.
otoh, if is is, the compiler will whine about line 2. or i must tell
the compiler not to whine at all. none of those is acceptable, imho,
since the warnings from the compiler are typically useful. that means
i want them, so p must be const and not const. so how do i frob the
return value location, since i don't want to treat it as const? i
can't assign through p (it's const) so i have to stuff the same
pointer value into something that's not const, but that means i need
to get rid of the const-ness. your "solution" merely offloads the
"problem" onto the application programmer, doesn't solve anything, and
the application programmer is left to invent their own __unconst()
the use of const, while tedious to some, is (when enforced by the
compiler) very useful. it means (for example) that you can much more
easily tell where your sigbus problems are coming from.
what you *want*, though you might not have realized it, is c++:
const char *strchr(const char *s, int c);
char *strchr(char *s, int c);
c can't do that. c++ also can't overload the function simply based on
return value, but that would be simple enough to fix...in a manner of
|-----< "CODE WARRIOR" >-----|
email@example.com * "ah! i see you have the internet
firstname.lastname@example.org (Andrew Brown) that goes *ping*!"
email@example.com * "information is power -- share the wealth."