C compiler incompatibility

Richard M. Mathews richard at locus.com
Sat Dec 29 11:25:38 AEST 1990


mcuddy at rutabaga.Rational.COM (Mike Cuddy) writes:
>I'm writing macros to deal with linked lists. (circular) and I'm having a spot
>of trouble with xlc ( this works fine on a SUN!):

>#define CLL_FOREACH(head,p) \
>	for((cll_t *)(p) = (head)->list.next ; \
>	    (p) != (head) ; (cll_t *)(p) = (p)->list.next)

Your expression is invalid.  Sun is allowing an illegal construct to go
by.  Many old compilers (including PCC) silently discarded these illegal
casts under a variety of circumstances.

ANSI says [all emphasis mine]:
	3.3.16
		An assignment operator stores a value in the OBJECT
		designated by the left operand.
	3.3.2.1
		An LVALUE is an expression ... that designates an
		OBJECT.
	3.3.1
		An identifier is a primary expression, provided it has
		been declared as designating an OBJECT (in which case it
		is an LVALUE) or a function....
	3.3.2.3
		A postfix expression followed by a dot ... is an LVALUE
		if the first expression is an lvalue.
		A postfix expression followed by an arrow ... is an LVALUE.
	3.3.3.2
		If [the unary * operator] points to an object, the result
		is an LVALUE designating the object.
	3.3.2.1
		The definition of the subscript operator [] is that E1[E2]
		is identical to (*(E1+(E2)))  [and thus I conclude that it
		is an LVALUE].

There is no comment in section 3.3.4, Cast Operators, which defines the
result of such an expression to ever be an lvalue.  Footnotes are not
officially part of the standard (according to section 1.4), but there
is an explicit statement in footnote 44 in section 3.3.4:
	44. A cast does not yield an lvalue.

A similar reading of K&R comes to the same conclusion.  The left side
of an assignment must be an lvalue, and cast operators do not create
lvalues.

Why should this be true?  Try creating a meaning for the following:
Assume that int and double are different size objects.  Then do
	int i;
	(double) i = 0;
Does this mean that the bytes past those of the object 'i' should be
modified by this expression?  Does it mean that some subset of the bytes
in (double)0 should be stored in the bytes of the object 'i'?  Which ones?
If you want to do something disgusting like this, you are expected to
use a disgusting construct such as:
	*(double *)&i = 0;
or
	double d = 0;
	i = *(int *)&d;
I know that PCC under BSD4.3 complains about "(double) i = 0" but not
about "(long) i = 0".  This inconsistency is not sanctioned by K&R or
ANSI.

In your case, I'm not sure how I would approach this.  The simplest hack
is to put (void *) on the right side of the assignments.  Much cleaner
would be to avoid all this type punning completely.  Just make sure that
each structure which will use CLL_FOREACH has a "next" and "prev" field
in it, and those fields point to structures of the correct type rather
than "struct list".

Richard M. Mathews			 Freedom for Lithuania
richard at locus.com				Laisve!
lcc!richard at seas.ucla.edu
...!{uunet|ucla-se|turnkey}!lcc!richard



More information about the Comp.unix.aix mailing list