[comp.lang.c] powerful expressions

wen-king@cit-vax.Caltech.Edu (King Su) (12/02/89)

References
Sender: 
Reply-To: wen-king@cit-vax.UUCP (Wen-King Su)
Followup-To: 
Distribution: 
Organization: California Institute of Technology
Keywords: 

While we are discussing styles, let's talk about simple expressions
that do a lot things.

	struct QUEUE { struct QUEUE *next;
		       <... other fields in the structure ...> } ;

	struct QUEUE *qhead, *qtail, *qnew;

I have concocted the following single expression that appends 'qnew' to
the queue formed by 'qhead' and 'qtail'.  The queue is null terminated,
'qhead' points to the first element of the queue, and 'qtail' points to
the last element of the queue:

	((qhead) ? (qtail = qtail->next = qnew)
		 : (qtail = qhead       = qnew))->next = 0;

Do you have any favorite C-expressions that you would like to share?

-- 
/*------------------------------------------------------------------------*\
| Wen-King Su  wen-king@vlsi.caltech.edu  Caltech Corp of Cosmic Engineers |
\*------------------------------------------------------------------------*/

Tim_N_Roberts@cup.portal.com (12/06/89)

In <12855@cit-vax.Caltech.Edu>, wen-king@cit-vax.Caltech.Edu (King Su)
shares:

>	((qhead) ? (qtail = qtail->next = qnew)
>		 : (qtail = qhead       = qnew))->next = 0;

I am truly sorry for the order-of-evaluation flood that I am surely about
to bring down upon myself, but...

Is this guaranteed to work?  Does ANSI require a sequence point in
(qtail = qtail->next = qnew) so that it works?  I have always been
hesitant to write something like that, because I felt that the compiler
could reasonably be expected to assign qnew to qtail first and thereby
screw up qtail->next.  Am I fearing needlessly?

TNR@cup.portal.com                  |  "Your Tax Dollars At Work."
...!sun!portal!cup.portal.com!tnr   |  If it wasn't so sad, it'd be funny.

bph@buengc.BU.EDU (Blair P. Houghton) (12/08/89)

In article <24735@cup.portal.com> Tim_N_Roberts@cup.portal.com writes:
>In <12855@cit-vax.Caltech.Edu>, wen-king@cit-vax.Caltech.Edu (King Su) shares:
>>	((qhead) ? (qtail = qtail->next = qnew)
>>		 : (qtail = qhead       = qnew))->next = 0;
>
>I am truly sorry for the order-of-evaluation flood that I am surely about
>to bring down upon myself, but...
>
>Is this guaranteed to work?  Does ANSI require a sequence point in
>(qtail = qtail->next = qnew) so that it works?  I have always been
>hesitant to write something like that, because I felt that the compiler
>could reasonably be expected to assign qnew to qtail first and thereby
>screw up qtail->next.  Am I fearing needlessly?

Fear no more.

The assignment operators group right-to-left.  That is

	qtail->next = qnew

is performed before

	qtail = qtail->next

is performed.

				--Blair
				  "K&R I, p. 191, for
				   what that's worth..."

wen-king@cit-vax.Caltech.Edu (King Su) (12/08/89)

In article <24735@cup.portal.com> Tim_N_Roberts@cup.portal.com writes:
>In <12855@cit-vax.Caltech.Edu>, wen-king@cit-vax.Caltech.Edu (King Su)
<shares:
>
<>	((qhead) ? (qtail = qtail->next = qnew)
>>		 : (qtail = qhead       = qnew))->next = 0;
<
>I am truly sorry for the order-of-evaluation flood that I am surely about
<to bring down upon myself, but...
>
<Is this guaranteed to work?

Yes.

Since the posting of the article, I have received exactly two replies.
One contains a better way to do the same thing:

    From: eggert@burns.twinsun.com (Paul Eggert)

		struct QUEUE *qhead = 0, **qtail = &qhead, *qnew;

	To append:

		*(qtail = &(*qtail=qnew)->next) = 0;

The other is a mild criticism.  To which my answer is that I now tend
use such expressions only in macros.  I used to put them in the program
body, but I have been doing less of that because it sometimes happens
that, as I was going through my old programs, I became totally
flabbergasted by some of the stuff I wrote.
-- 
/*------------------------------------------------------------------------*\
| Wen-King Su  wen-king@vlsi.caltech.edu  Caltech Corp of Cosmic Engineers |
\*------------------------------------------------------------------------*/

rhg@cpsolv.UUCP (Richard H. Gumpertz) (12/09/89)

In article <5040@buengc.BU.EDU> bph@buengc.bu.edu (Blair P. Houghton) writes:
>In article <24735@cup.portal.com> Tim_N_Roberts@cup.portal.com writes:
>>In <12855@cit-vax.Caltech.Edu>, wen-king@cit-vax.Caltech.Edu (King Su) shares:
>>>	((qhead) ? (qtail = qtail->next = qnew)
>>>		 : (qtail = qhead       = qnew))->next = 0;
...
>Fear no more.
>
>The assignment operators group right-to-left.  That is
>
>	qtail->next = qnew
>
>is performed before
>
>	qtail = qtail->next
>
>is performed.

X3J11/88-158, page 10, line 22: "The grouping of an expression does not
completely determine its evaluation."

X3J11/88-158, page 39, line 5: "Between the previous and next sequence
point an object shall have its stored value modified at most once by the
evaluation of an expression.  Furthermore, the prior value shall be
accessed only to determine the value to be stored."

X3J11/88-158, page 53, line 30: "The side effect of updating the stored
value of the left operand [of an assignment operator] shall occur
between the previous and the next sequence point."

X3J11/88-158, page 53, line 33: "The order of evaluation of the operands
[of an assignment operator] is unspecified."

Much as I would like to agree that the code is safe, I can't find anything
in the standard that guarantees it.  I think the standards committee may
have (intentionally?) blown this one; can anyone prove me wrong?

The following should always work (assuming NULL is defined by the
appropriate #include):
   (qhead ? qtail->next = qnew : qhead = qnew), (qtail = qnew)->next = NULL;

By the way, I would like to have written
   (qhead ? qtail->next : qhead) = qnew, (qtail = qnew)->next = NULL;
but lvalues are converted to rvalues in this context so THIS WON'T WORK!

-- 
===============================================================================
| Richard H. Gumpertz rhg%cpsolv@uunet.uu.NET -or- ...uunet!amgraf!cpsolv!rhg |
| Computer Problem Solving, 8905 Mohawk Lane, Leawood, Kansas 66206-1749      |
===============================================================================

bph@buengc.BU.EDU (Blair P. Houghton) (12/10/89)

In article <462@cpsolv.UUCP> rhg@cpsolv.uucp (Richard H. Gumpertz) writes:
>In article <5040@buengc.BU.EDU> bph@buengc.bu.edu (Blair P. Houghton) writes:
>>>In <12855@cit-vax.Caltech.Edu>, wen-king@cit-vax.Caltech.Edu (King Su) shares:
>>>>	((qhead) ? (qtail = qtail->next = qnew)
>>>>		 : (qtail = qhead       = qnew))->next = 0;
>...
>>The assignment operators group right-to-left.  That is
>>	qtail->next = qnew
>>is performed before
>>	qtail = qtail->next
>
>X3J11/88-158, page 10, line 22: "The grouping of an expression does not
>completely determine its evaluation."

This is distasteful and will continue to be distasteful so long as
assignment is considered an operator.  Could someone please email me a
copy of the rationale for this rule?

>X3J11/88-158, page 53, line 30: "The side effect of updating the stored
>value of the left operand [of an assignment operator] shall occur
>between the previous and the next sequence point."

Huh?

>X3J11/88-158, page 53, line 33: "The order of evaluation of the operands
>[of an assignment operator] is unspecified."

This one speaks of the left and right sides of a single
assignment-operator, and seems to controvert the (formerly) specified
right-to-left grouping of strings of assignments.

>Much as I would like to agree that the code is safe, I can't find anything
>in the standard that guarantees it.  I think the standards committee may
>have (intentionally?) blown this one; can anyone prove me wrong?

Especially elucidations on the possibility of that "intentionally."

Doug?

>The following should always work (assuming NULL is defined by the
>appropriate #include):
>   (qhead ? qtail->next = qnew : qhead = qnew), (qtail = qnew)->next = NULL;

I think it's time just to do:

	if (qhead)
	    qtail->next = qnew;
	else
	    qhead = qnew;

	qtail = qnew;
	qtail->next = NULL;

Except for the loss of the extra capabilities of an expression.

				--Blair
				  "No pain, uh, no pain."