Topic: Should order of evaluation be undefined?


Author: dwr@cci632.cci.com (Donald W. Rouse II)
Date: Mon, 18 Jan 1993 18:03:03 GMT
Raw View
In article <1993Jan18.095427.20883@lut.ac.uk> R.M.Chandler@lut.ac.uk (Richard Chandler) writes:
[ stuff about f(++x,++x) causing undefined args to be passed to f() deleted]
>
>What I'm having difficulty with, is understanding why it's undefined, when
>it actually affects the programmer's meaning. A few people have written back
>privately explaining this is a comma seperator, rather than an operator. As
>far as I know, the comma operator works from left to right, seperating items
>inbetween brackets. OK so this is a function call, and is different, but
>the compiler is changing the meaning of my program.
>
[...]
>
>PS In reference to the earlier response about me daring to use this news group,
>I consider this to be a standards issue, it isn't a user question. [...]

OK, let's make this a standards issue.
The ANSI C standard says that the order of evaluation
of function arguments is undefined.
I assume that the draft C++ standard carries similar language.
Should it?

My opinion is yes.
The reason has to do with the efficiency of C/C++.
Let's assume that a compiler can generate better code
for a function call if it can evaluate its arguments
right-to-left (or scrambled, or whatever).
Why should it have to generate less efficient code
in order to evaluate its arguments left-to-right?
In most cases, the order of evaluation is unimportant,
because there are no overlapping side-effects.
Therefore, let the compiler generate the most efficient
code possible.
This is the same reason why there is no standard size
for short or long integers.

"OK", you might say, "Let the compiler evaluate arguments
in any order when there are no overlapping side effects,
but from left to right when there are."
The problem with this is that it is difficult to tell
if there are overlapping side effects.

For example:
 file1.c:
 extern int i, *ip;
 int f1() {return ++i;}
 int f2() {return ++i;}
 void f3() {ip = &i;}

 file2.c:
 extern int f1(), f2();
 extern void f3();
 static int j = 4;
 int i = 1, *ip = &i;
 main ()
  {
  printf ("%d %d\n", f1(), f2());
  f3();
  printf ("%d %d\n", i, *ip);
  }

In both printfs, there are overlapping side effects
that the compiler cannot possibly know about
if it compiles file1.c and file2.c separately.

"OK", you might say, "Let the compiler evaluate arguments
in any order when there are is
no _possibility_ of overlapping side effects,
but from left to right when there is."
The problem is, in most cases that the compiler
would have to generate the less efficient code,
the programmer knows that there are
no overlapping side effects,
and wants the compiler to generate the most
efficient code.

On a side note,
I think your compilers should have warned you about
overlapping side effects in the example you gave.

On another side note,
I have used the term "overlapping side effects"
throughout this followup.
Is there a more official computerese term for it?

Thank you, and sorry for the length of this posting.
I wanted to try to cover everything.