Subject: Re: toolchain/22118: make won't compile with -Wcast-qual
To: NetBSD Toolchain Technical Discussion List <tech-toolchain@NetBSD.org>
From: Greywolf <greywolf@starwolf.com>
List: tech-toolchain
Date: 07/18/2003 14:30:56
Thus spake Greg A. Woods ("GAW> ") sometime Today...

GAW> I have never said any such thing.  What I do want, and with GCC what I
GAW> do have, is an implementation of Standard C which gives me the ability
GAW> to know at compile time whether or not my code could potentially suffer
GAW> a bug that might result in an attempt to modify a constant.

Unfortunately (or fortunately, depending on your POV), GCC != "Standard C",
at least not strictly speaking, unless you count extensions to the standard
as part of the standard.

GAW> "const" would not have been necessary if the ANSI committee had done
GAW> their job properly and standardized the original C language instead of
GAW> inventing a new variant language.  (K&R, 1st edition, Appendix A, 2.5
GAW> (p.181):  "All strings, even when written identically, are distinct.")

[which is something that I think xstr managed to circumvent, thank
goodness, thus allowing one to reduce the amount of space used by
liberally sprinkled identical string constants.]

GAW> Hmmm -- yes, such as, for example, Smalltalk-80 or even Common LISP.

LISP is much more entertaining (at least from a certain POV (or so it
might (possibly) seem)) when applied to a spoken language (such as
(for example) English) :).

GAW> I am most certainly not trying to describe an ideal language -- as C is
GAW> anything but.  I am discussing the situation in the real-world for C
GAW> code that attempts to be portable regardless of whether the target
GAW> implementations it is to be compiled with are themselves strictly
GAW> compliant with the C Standard or not.

Off topic a bit:

Hm.  C is anything but an ideal language.  I'm sure a lot of folks out
there might agree with that, but I fail to see precisely why.  The points
I've heard against it are by and large:

	- lack of object-orientation, and
	- the ease by which bad code is able to be written.

To address the first one, I see that it might be a problem, but rarely.
I just don't see OO as a huge plus -- it usually generates much more
bloated code on output.

To address the second one, well, Hell's bells, people, if you have a sharp
sword (and C is still sharper than most (no pun intended)), you're
occasionally going to lose control of the blade and cut yourself once in a
while.

GAW> That very first point I tried to make was primarily that any attempt to
GAW> invent a DECONST() macro/function/cast/whatever was clearly and
GAW> blatantly wrong on all counts and secondarliy that the very attempt to
GAW> justify such a construct always relies only on some earlier mistake
GAW> caused by either trying to add a "const" qualifier to a parameter where
GAW> it did not belong or else making the mistake of assuming that string
GAW> literal constants were not at least implicitly "const"-qualified.
GAW>
GAW> I.e. if you think you need DECONST() then you are mistaken as the real
GAW> problem is elsewhere.  So far nobody has demonstrated even a hint of a
GAW> standard (de facto or otherwise) API which mis-uses "const" and thus
GAW> would require DECONST() tricks to either implement or use it without
GAW> changing the original API (minutely, and in an ABI-compatible fashion).

I would say, then, that most places const is used it oughtn't be, such as
common areas intended to be potentially both written and read.  If you
The Programmer *really* do not intend for the storage path to be modified,
fine, use const.  Otherwise, leave it out.

GAW> I'm also very happy to learn from this discussion that GCC's use of
GAW> writable storage for "char foo[]" initializers is likely to be mirrored
GAW> by other conforming Standard C implementations.  Up until now this was
GAW> something I had assumed was a GCC specific behaviour and would may not
GAW> be copied by a strictly conforming implementation.
GAW>
GAW> (I suppose I also get somewhat worked up over this kind of issue because
GAW> of the fact that it would have been avoided in the first place if ANSI C
GAW> had not invented new and strictly unnecessary constructs such as shared
GAW> storage for string literals.  Grrr.  :-)

I think, more appropriately, it would seem that they were only trying to
establish a standard by permitting string literals to be written to.

[NOTE: went back and re-read what you meant regarding shared storage, and
I get it (shared storage does not necessarily denote RO or RW).  I agree
with this viewpoint; even xstr didn't allow shared storage -- it provided
a reference into the storage with an index into an array of pointers.
But I digress...]

Such behaviour, as I understand it, was never guaranteed to be allowed;
the fact that it Just Worked under, i.e. 4.2BSD on the VAX, for example,
was fortuitous, IIRC.  There were warnings sprinkled all over the place
-- especially in various newsgroups (comp.lang.c) -- which stated that
writable initialised data was not a guarantee; in fact, I seem to remember
one implementation which did not allow things in the .data section to be
explicitly modified -- one had to copy them out of the initialised variable
into dynamic storage in order to use them.

Damned if I can remember which implementation that was, but I'm glad to be
rid of it.

Just for the record, I threw this together and compiled with Sun's
(unbundled) cc as well as gcc, and here's what I discovered from the
resulting .s files, near's I can tell:

/* start */
/* GCC */
char textbar[]="Text?"; /* BOTH: .data [RW] */
char textbar2[14] = "Is this text?";    /* BOTH: .data [RW] */
char *textptr="Textpointer?";   /* GCC: .rodata, Sun: .data1 [RW] */
int unalloc;    /* GCC: .text, Sun: .data */
int alloc=2;    /* BOTH: .data */


char *text(argc, argv)
int argc;
char *argv[];
{
    char *textest = "is this in .text?";    /* G: .rodata, S: .data1 [RW] */
    char textest2[] = "How about this?";    /* BOTH: .rodata */
    char textest3[9] = "Or this?";          /* BOTH: .rodata */
    int ialloc = 4;
    int iunalloc;
    union {
            char u_c;
            short u_s;
            long u_l;
            double u_align;
    } c[1];
}

/* end */

I find it interesting, the different treatment of char * by the two
compilers...

				--*greywolf;
--
NetBSD: the second best thing you can get for free.