Evaluation order of assignment.

Wayne A. Throop throopw at xyzzy.UUCP
Sat Aug 20 04:19:25 AEST 1988


> schmidt at 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      <the-known-world>!mcnc!rti!xyzzy!throopw



More information about the Comp.lang.c mailing list