Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!lll-crg!nike!sri-spam!sri-unix!hplabs!hp-sdd!ncr-sd!ncrcae!ece-csc!mcnc!rti-sel!dg_rtp!throopw From: throopw@dg_rtp.UUCP (Wayne Throop) Newsgroups: net.lang.c Subject: Re: Must casting destroy lvalueness? Message-ID: <663@dg_rtp.UUCP> Date: Mon, 27-Oct-86 16:48:50 EST Article-I.D.: dg_rtp.663 Posted: Mon Oct 27 16:48:50 1986 Date-Received: Mon, 3-Nov-86 21:33:30 EST References: <4617@brl-smoke.ARPA> <657@dg_rtp.UUCP> <55@cartan.Berkeley.EDU> Lines: 143 Summary: desJardins says "No." I say "MUST SO, MUST SO, MUST SO!!!" David is very misinformed on this question. It is apparently an easy thing to do, since mis- and dis- information about casts and pointers in C is so common. Never fear, I'll point out, case by case, where he went wrong. :-) > desj@brahms (David desJardins) >> throopw@dg_rtp.UUCP (Wayne Throop) >>> Stuart Gathman >>>> ((OBJECT)pointer)++ >>>A more correct syntax: >>> char *pointer; >>> pointer += sizeof (OBJECT); >>>And clearer to boot if you ask me. > Wrong if you ask me. First, in the original example it is clear that > OBJECT is a pointer type. And second, your sample code does not work, and > can not readily be fixed, if sizeof (char) != 1. True, true. But ANSI is likely to decide that sizeof(char) MUST ALWAYS BE one (and I think this is universally true on existing implementations... if I'm wrong, somebody let me know). The relevant incantation from the draft standard (3.3.3.4): The sizeof operator yields the size (in bytes) of its operand, which may be an expression of the parenthesized name of a type. [...] When aplied to an operand that has type char, unsigned char, or signed char, the result is 1. In order to make Stuart's method work (since OBJECT is a pointer type, as David correctly points out) one must (oddly enough) say: pointer += sizeof( *((OBJECT)0) ); Now, in his critique of my earlier posting, David falls into *really* serious error, as follows: >>I sayeth that if thou wishest to taketh an object as a different typeth, >>thou mayest do so. However, casts are not the way to do this in C, and >>the practice is not portable. If you must take the bits of one pointer >>type as being those of another pointer type, use >> (*((some_type **)&p))++ > In C, pointers and lvalues are the same thing (there is a bijection given > by & and *). False. The "&" operator does not work on bit fields nor register values, and yet these are lvalues. In fact, close reading of K&R, H&S, and the draft ANSI standard make it clear that not all legal lvalues map to legal pointer typed expressions (via &), nor do all legal pointer typed expressions map to legal lvalues (via *). > Essentially, = (and the other assignment operators) automatic- > ally take the address of their left-hand arguments, in much the same way that > setq/set! quote their first arguments. Again, false, and for about the same reasons. The notion of an assignment operator implicitly quoting the assignee is nice, somewhat elegant, and a familiar notion in LISP. But don't be fooled, folks. C is not now and has never been LISP, and C does not have this simple, elegant, unifying notion. C has "lvalues" instead. > [expansion of this misunderstanding of lvalue, omitted] > So I would conclude that the statement ((OBJECT) pointer)++ should be > interpreted as > * ((OBJECT *) &pointer) = (OBJECT) pointer + 1; And you would be wrong. > [more discussion based on the misunderstanding of lvalue, omitted] > At any rate they are all legal C. It is important to note that the original construct, ((OBJECT)pointer)++ is *DEFINITELY* *NOT* legal C. (It is not clear to me whether David is claiming that it IS legal... in any case it is important to note that it is NOT.) >> [...] use unions like God intended. Don't try to pervert casts to do >>something they weren't intended for. Casts convert, unions take-as. >>The take-as operation is inherently non-portable. > But the point is that casts of pointers *don't* convert. Either they > simply take-as, or they are meaningless. Absolutely wrong. Casts *ALWAYS* convert. Harbison and Steele say (on page 152): The cast causes the operand value to be converted to the type named within the parentheses. Any permissible conversion may be invoked by a cast expression. The draft ANSI document says (3.3.4): Preceeding an expression by a parenthesized type name converts the value of the expression to the named type. K&R say similar things in several places. (I'll let y'all look those up by y'selfs.) Another problem in the above passage is that David seems to have a serious case of "pointers is pointers" disease. Pointers to different types may (and often do) have *COMPLETELY* *DIFFERENT* bit-wise formats. Thus, the notion of converting an (int *) typed pointer to a (char *) typed pointer is hardly "meaningless". On the DG MV architecture (to randomly choose an example I'm modestly familiar with) these two pointer types have the "ring field" in different locations, and one has an indirect bit that the other lacks. A pointer to a given word needs to be *CONVERTED* *TO* *A* *DIFFERENT* *FORMAT* to be a pointer to the first byte in that word. This is just what casts were intended for (first and foremost in the arithmetic types, but clearly useful and necessary for pointers also). David, I'm not sure who told you "casts of pointers don't convert". Find whoever told you that base canard, and pummel some sense into the miscreant, willya? You have been severely misled. > So, if the language allows casting > of pointers, then I see no valid reason to complain when the programmer uses > this feature (especially since essentially all C implementations make it > impossible to avoid when using any sort of dynamic memory allocation!). Yes, casting is necessary to write a memory allocator in any even nearly portable way. *BUT*, casts are *STILL* conversions, *NOT*, *NOT*, *NOT* taken-ases. > And if he is allowed to use casting, why force him to write *((foo *) &x) = > when (foo) x = will do? Granting the implicit hypothetical, no reason, of course. But (foo)x *won't* do. > At any rate, I think that the answer to the question > "*Must* casting destroy lvalues?" is clearly "No." Well, waxing philosophical, I agree. That is, I rather expect that one can come up with some consistent set of semantics that will give meaning to the notion of a cast as an lvalue. But it is well to keep in mind: (deep breath, all together now) these semantics won't be *C* semantics. -- "Pwease Mistew Game Wawden, ... can you teww me what season it WEAWWY is?" "Why SOIT'NY, m'boy! It's BASEBALL season!" --- (Elmer and Bugs, of course) -- Wayne Throop !mcnc!rti-sel!dg_rtp!throopw