[net.lang.c] ++ operator

mp@mit-eddie.UUCP (Mark Plotnick) (12/26/83)

dave@taurus notes:
	Uh-uh:
		if(*in++ == *in++)

	...

	Also, for those of little faith, there are actually C compilers that
	will take the non-obvious meaning of this (e.g. the PDP-11 cc), and do
	the tests then do both increments in one go after the statement,
	so BE WARNED.

I just tried this with the V7 cc, 4.1bsd pcc, and VAX-11 C compilers, and in
each case two increments were done.

The reference manual is vague here, but a good rule of thumb is that
foo++ is equivalent to ((foo=foo+1)-1).  I don't know of any exceptions
to this off-hand, although I heard that a pcc author was once thinking of
delaying the postincrement of function args until after the function call
[i.e. f(i++) would be equivalent to (temp=f(i),i++,temp) ].

Since there are still quite a few C compilers being written from
scratch out there, it would really help if someone were to come up with
a precise, consistent definition for how the postincrement and
postdecrement operators should behave.  Ditto for enum, void,
unsigned chars, non-integer bitfields, etc.

	Mark

minow@decvax.UUCP (Martin Minow) (12/27/83)

Mark Plotnik asks for a "precise, consistent definition" of the
semantics of ++ and -- (among other things).  The definition
is "compiler dependent", but all side effect operators will
be evaluated when control passes to the next statement.
(It may be the case that side-effect operations will be evaluated
before passing over , && or ||, but I wouldn't bet on it.

Vax-11 C (on VMS) is very willing to evaluate auto-increment
operators at "unusual" times.  For example, consider the following:

	int	stack[123];		/* Evaluation stack	*/
	int	*stack_pointer = stack;
	#define push(x)	(*--stack = x)	/* Stuff into the stack	*/
	#define pop()	(*stack++)	/* Get from the stack	*/

	int
	eval(operator)
	{
		switch (operator) {
		...
		case OP_ADD:
		     push(pop() + pop());
	...

You may think that "*--stack = *stack++ + *stack++;" will "do the
right thing", but it is (by demonstration) compiler dependent.
(I found that out the hard way -- the original had the misleading
comment "don't need a temp variable since addition is commutative").
The correct expression of the above is:

		    temp = pop();
		    temp += pop();
		    push(temp);

Martin Minow
decvax!minow

jreuter@cincy.UUCP (Jim Reuter) (12/28/83)

dave@taurus notes:
	Uh-uh:
		if(*in++ == *in++)

	...

	Also, for those of little faith, there are actually C compilers that
	will take the non-obvious meaning of this (e.g. the PDP-11 cc), and do
	the tests then do both increments in one go after the statement,
	so BE WARNED.
mp@mit-eddie replies:
	I just tried this with the V7 cc, 4.1bsd pcc, and VAX-11 C compilers,
	and in each case two increments were done.

(The implied meaning is that they were done in the proper place.  They
are, I just tested it.)

The real problem here is the ORDER of the increments.  In this example,
order would not matter.  A nice simple example of ordering problems shows
up in the v7 Ritchie compiler:

	int i = 0;

	printf(" %d %d %d %d\n", i++, i++, i++, i++ );

which produces

	3 2 1 0

	Jim Reuter
	(decvax!cincy!jreuter)

donn@sdchema.UUCP (Donn Seeley) (01/04/84)

Not that this constitutes a holy war, but I strongly agree with Dave
Lukes that the order of evaluation of side effects is (and should be)
undefined.  Even if side effects had a dependable order of evaluation,
programs that depended on this order would be very difficult for the
programmer in the street to interpret.  I'm not (necessarily) an
advocate of functional programming but I don't think that this attitude
is unreasonable.  Also, by restricting the order of evaluation of these
side effects you might disallow some (otherwise) reasonable
optimizations.

I really wanted to contribute an example of a compiler difference in
order of evaluation of side effects.  This incident actually happened
-- you can try it for yourself if you don't believe it.  Some poor
researcher's C program to convert plot data ran on V6 on an 11/40 but
broke under 4.1 on the VAX.  (We ran phototypesetter V7 C on the
11/40, if it makes any difference.)

When I looked at his program I discovered code like the following:

	...
	int data[8];
	int *R;
	int count;
	...
	R = data;
	count = *R++ + *R++ + *R++ + *R++ + *R++ + *R++ + *R++ + *R++;
	...

Some unthinking systems programmer had casually informed the poor
researcher that pointer references were faster than subscript
indirection.  From there it was a short step to concluding that side
effects are done from left to right (obvious, huh? -- well, at least
you TYPE the side effects in from left to right).  When he compiled and
ran the program on V6, it worked just as he expected.  Unfortunately
the VAX compiler (with -O) does all of the increments AFTER doing all
of the additions...  (And clumsily, too: it does all the increments
separately instead of conflating them into a single add.)

So, yes, commonly used C compilers DO differ in order of evaluation of
postincrement and other side effects.

Donn Seeley    UCSD Chemistry Dept. RRCF    ucbvax!sdcsvax!sdchema!donn