donn@sdchema.UUCP (06/04/83)
Reference: mit-eddi.218 mit-eddie!mp brings up an interesting issue of portability: I had some problems compiling some V7 code on 4bsd; wherever the author had expressions such as "(char *)ptr_to_struct = ptr_to_char", the compiler complained. The intuition here is that the left hand side should be interpreted as using the variable ptr_to_struct as a character variable, but in some sense it is still the same variable; you should be able to assign to it, for example. Unfortunately this intuition is false. This is not entirely clear from the text; as mit-eddie!mp notes, K&R say on p. 42: ...[E]xplicit type conversions can be forced ("coerced") in any expression with a construct called a cast. In the construction ( type-name ) expression the expression is converted to the named type by the conversion rules [on p. 41]. The precise meaning of a cast is in fact as if [the] expression were assigned to a variable of the specified type, which is then used in place of the whole construction. The inference which the writer of the V7 programs made is that the "temporary variable" has the same address as the operand of the cast and hence it is reasonable to assign to it. However, this inference is not as reasonable as it might look. For example, what should the compiler do with this? int i; (double) i = 3.141592654; A double on most machines is considerably larger than an int. If the compiler treats the cast as being a double with the same address as i, then whatever follows i in memory is going to get clobbered. One might argue that this is an expected side-effect which users should know to look out for, but it seems pretty dangerous to me, especially when there is a more explicit syntax that accomplishes the same thing: * (double *) & i = 3.141592654; I think the inference arises because we 'know' that a conversion of pointer types does not change the value of a pointer. Needless to say, this is external to the problem of interpreting casts, and it probably isn't portable either. The actual grammar of C in K&R bears out the interpretation that a cast should not be assigned to. A cast is explicitly an expression, not an lvalue, and only lvalues may be assigned to; thus the PCC (the VAX compiler) is actually doing the right thing. (Even though lvalues and expressions are not distinguished in the PCC's YACC grammar! Lvalues are found during the static semantics checking.) I still don't know why Dennis Ritchie's compiler lets these casts through. At any rate the "correct" way of writing expressions like (char *) ptr_to_struct = ptr_to_char; is ptr_to_struct = (struct foo *) ptr_to_char; I think this looks better too... Donn Seeley UCSD Chemistry Dept. RRCF ucbvax!sdcsvax!sdchema!donn (619) 452-4016 sdamos!donn@nprdc