Path: utzoo!utgpu!water!watmath!clyde!att!pacbell!ames!haven!umd5!uvaarpa!mcnc!rti!xyzzy!throopw From: throopw@xyzzy.UUCP (Wayne A. Throop) Newsgroups: comp.lang.c Subject: Re: Evaluation order of assignment. Message-ID: <1031@xyzzy.UUCP> Date: 19 Aug 88 18:19:25 GMT References: <957@orion.cf.uci.edu> Organization: Data General, RTP NC. Lines: 77 > schmidt@bonnie.ics.uci.edu (Douglas C. Schmidt) > Is the following always guaranteed to produce the "intended" result: > > struct list { > int item; > struct list *next; > }; > > struct list foo() > { > struct list head; > > return(head->next = head = (struct list *) malloc(sizeof(struct list))); > } > > My intention is to create a dummy node in a circularly-linked list, > and assign the dummy node's next field to point to the head of > the list. Since assignment associates from right-to-left this > will alway work, right (cryptic style notwithstanding !! ;-)). This intent is very hard to deduce from the code, since the code is, in fact, illegal C. To whit, lint has this to say about the return statement: x1.c ============== (10) operands of = have incompatible types (10) operands of RETURN have incompatible types (10) warning: head evaluation order undefined warning: illegal combination of pointer and integer: (10) operator = warning: struct/union or struct/union pointer required (10) Further, another tool found this extra problem: ./x1.c 10 incorrect expression type The expression is: head->next Its type is: struct list The expected type is: a pointer type So, translating "foo" to be what was probably meant: struct list *foo(){ struct list *head; return(head->next = head = (struct list *) malloc(sizeof(struct list))); } And running THAT through lint, we find: (9) warning: head evaluation order undefined SO, the final result we come up with is: "No, that code will not portably do what you intend." The reason for this is that a side-effect takes place to the variable "head" within the expression, and the sequencing of side effects are not guaranteed in C. Thus, the head in "head->next" might be pointing to the newly allocated node, or to whatever the garbage it contained was pointing to. So, the return would have to be coded like so, introducing a sequence point to guarantee order of evaluation: return(head = (struct list *) malloc(sizeof(struct list)), head->next = head ); > thanks, You're welcome. -- Standards should be discovered, not decreed. --- Padlipsky -- Wayne Throop!mcnc!rti!xyzzy!throopw