mcuddy@rutabaga.Rational.COM (Mike Cuddy) (12/29/90)
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!): ------- cut here ------- typedef struct cll_f { struct list *next; struct list *prev; } cll_t; struct foo { cll_t list; int a, b, c; /* ... more stuff ... */ }; #define CLL_FOREACH(head,p) \ for((cll_t *)(p) = (head)->list.next ; \ (p) != (head) ; (cll_t *)(p) = (p)->list.next) void traverse(list) struct foo *list; { struct foo *p; CLL_FOREACH(list,p) { /* ... output data ... */ } } ------ cut here ------- % cc foo.c 23 | for((cll_t *)(p) = (list)->list.next ; (p) != (list) ; (cll_t ........a..................................................b...... a - 1506-025: (S) Operand must be a modifiable lvalue. b - 1506-025: (S) Operand must be a modifiable lvalue. *)(p) = (p)->list.next) { ------ extracted from my xlc.cfg: ------- * standard c compiler aliased as cc cc: use = DEFLT crt = /lib/crt0.o mcrt = /lib/mcrt0.o gcrt = /lib/gcrt0.o libraries = -lc proflibs = -L/lib/profiled,-L/usr/lib/profiled options = -H512,-T512, -qlanglvl=extended, -qnoro * common definitions DEFLT: xlc = /usr/lpp/xlc/bin/xlcentry as = /bin/as ld = /bin/ld options = -D_IBMR2,-D_AIX,-bhalt:4 ldopt = "b:o:e:u:R:H:Y:Z:L:T:A:V:k:j:" --Mike Cuddy "...He's a UNIX hack and he's okay, he works all night and he sleeps all day..."
richard@locus.com (Richard M. Mathews) (12/29/90)
mcuddy@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@locus.com Laisve! lcc!richard@seas.ucla.edu ...!{uunet|ucla-se|turnkey}!lcc!richard