[comp.lang.c] stack quirk?

brianh@hpcvia.CV.HP.COM (brian_helterline) (07/27/90)

>Hi everyone.  Here's one.  I hope it is not as simple as my last one,
>you remember( gets() ).  I'm running the following program, and I'm not 
>getting out what I think I should be( so what else is new!).  Any ideas?

>#include <stdio.h>
>main()
>{
>int i= 0;
>printf("\n%d %d\n", ++i, ++i);	/* output is: 2 1, I expected 1 2 */
>i= 0;
>printf("%d %d\n", ++i, i++);	/* output is: 2 0, I expected 1 1 */
>i= 0;
>printf("%d %d\n", i++, ++i);	/* output is: 1 1, I expected 0 2 */
>i= 0;
>printf("%d %d\n", i++, i++);	/* output is: 1 0, I expected 0 1 */
>}
>
>Please send e-mail:  ndimas@pikes.denver.colorado.edu
>
>
>				Thank You 
>				Nicholas Dimas
>----------

	The output you got should is correct.  The arguments to
	printf() [or any function] are pushed on to the stack
	right to left so they are in the correct order for
	printf() to pop them off when needed.  If you evaluate
	each expression above right-to-left, you will "expect"
	exactly what the output was.  Also note that each argument
	to printf() is a single expression, so once it is evaluated,
	the ++ operator can do the increment and then move on to the
	next expression.  As an example, printf( "%d %d\n", i++, ++i );

	arg1 = "%d %d\n"
	arg2 = i++;
	arg3 = ++i;

	if i=0 to start, and we evaluate right-to-left,
	arg3 = 1 and i = 1
	arg2 = 1 and _then i = 2
	arg1 = "%d %d\n";

	I am not certain as to what ANSI specifies about whether this
	behavior is correct or not.  I am just trying to describe
	what is happening.  It is usually a bad idea to use ++ operators
	on the same variable more than once in _ANY_ expression.

	Hope this helps,

steve@taumet.com (Stephen Clamage) (07/29/90)

brianh@hpcvia.CV.HP.COM (brian_helterline) writes:

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

|	The output you got should is correct.  The arguments to
|	printf() [or any function] are pushed on to the stack
|	right to left so they are in the correct order for
|	printf() to pop them off when needed.  If you evaluate
|	each expression above right-to-left, you will "expect"
|	exactly what the output was.

There is no guarantee in what order ++i and i++ will be evaluated,
nor whether the incremented values will be stored before or after
the second of the two is evaluated.  Consequently, there is no
way to predict what the output will be.  The ANSI C standard
explicitly says that you cannot count on when the "side effects"
will take place, except that they will be complete before the
function is called.  C texts warn (or should warn) about modifying
a variable which is referenced more than once in the same expression.
Such code is often not warned-about by compilers, and may produce
surprisingly different results on different systems.

-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

jc@atcmp.nl (Jan Christiaan van Winkel) (07/30/90)

From article <359@taumet.com>, by steve@taumet.com (Stephen Clamage):
> brianh@hpcvia.CV.HP.COM (brian_helterline) writes:
> 
> |>printf("\n%d %d\n", ++i, ++i);
> |> etc
> Such code is often not warned-about by compilers, and may produce
> surprisingly different results on different systems.

Lint's usefulness is too often underestimated. Whenever a program does not
produce the results I expect, the first thing I'll do is use lint. I cannot
stress this enough! USE LINT
cat tst.c

main()
{
  int i;
  i=5;

  (void)printf("\n%d %d\n",++i, ++i);
  return 0;
}

lint tst.c
tst.c
==============
(6)  warning: i evaluation order undefined

JC
-- 
Jan Christiaan van Winkel              Tel: +31 80 566880     jc@atcmp.nl
AT Computing       P.O. Box 1428       6501 BK Nijmegen       The Netherlands

tomr@ashtate (Tom Rombouts) (08/01/90)

In article <359@taumet.com> steve@taumet.com (Stephen Clamage) writes:
>brianh@hpcvia.CV.HP.COM (brian_helterline) writes:
>
>|>printf("\n%d %d\n", ++i, ++i);
>
>There is no guarantee in what order ++i and i++ will be evaluated,

Just to tie this into the recent "value of lint" thread, this is
exactly the type of thing that a good lint will flag.  ("Warning:
expression depends on order of evaluation", etc.)  Readers of this
group may remember a "bug" fragment of code from MSC 5.1 to 6.0
that seemed to operate differently a few months ago that Gimpel
PC-Lint correctly flagged.

Tom Rombouts  Torrance Techie  tomr@ashtate.A-T.com  V:(213) 538-7108

scs@adam.mit.edu (Steve Summit) (08/02/90)

In article <31530012@hpcvia.CV.HP.COM> brianh@hpcvia.CV.HP.COM (brian_helterline) writes:
(in response to a code fragment like printf("%d %d\n", i++, i++);)

>	The arguments to
>	printf() [or any function] are pushed on to the stack
>	right to left so they are in the correct order for
>	printf() to pop them off when needed.

Though correct for many machines, this is not true in general,
for the C language neither mandates stack direction nor the
existence of a stack.  When you hear that evaluation order, and
hence the behavior of an expression containing multiple side
effects, is "undefined," it means that you cannot predict and
should not know how various machines will do it, and that
different machines may do it differently.  To quote our good
friends K&R, "Naturally, it is necessary to know what things to
avoid, but if you don't know _how_ they are done on various
machines, that innocence may help to protect you."

>	I am not certain as to what ANSI specifies about whether this
>	behavior is correct or not.

ANSI C reaffirms that evaluation order in such cases is
undefined, and furthermore (so I have been told) gives compilers
license to reject programs depending on undefined evaluation
order at compile time, without even flipping a coin and picking
an order.

>	It is usually a bad idea to use ++ operators
>	on the same variable more than once in _ANY_ expression.

Correct, except that the operative adverb is "always."

See the frequently asked questions list for a bit more on this
topic.

                                            Steve Summit
                                            scs@adam.mit.edu