Topic: i=i++ : order of evaluation
Author: Alexander Gootman <gtm@cer.nsk.su>
Date: Fri, 12 Nov 93 11:03:22 +0300 Raw View
volpe@bart.crd.ge.com (Christopher R. Volpe) writes:
:In article <AConxri8t2@cer.nsk.su>, Alexander Gootman <gtm@cer.nsk.su> writes:
:>Consider the expression in context of global `int i=0;' definition:
:>
:>i=i++; // (1)
:>Cfront and Zortech evaluate (1) to 0 but Boralnd gives 1 .
:Since "i" is just an int, this statement is the same in C++ as at is in C,
:which is undefined, since the object is modified twice between sequence
:points.
:An operator in C (and I hope this is true for C++ except in cases where
:operators are explicitly overloaded) is not the same as a function call. In
:a function call, there is a sequence point after the evaluation of all the
:function arguments and immediately before the actual transfer of control.
:However, with an operator, there is no sequence point between the evaluation
:of the operands and the actual invocation of the operator.
Also, jimad@microsoft.com (Jim Adcock) writes:
|These issues were well-covered in the ANSI/ISO C Standard, where there
|was a clear model of execution, with sequence points etc. That standard
|says that accessing any variable more than once for modification between
|two adjecent sequence points is undefined. In the above expression
|i is accessed twice for modification, and thus is undefined.
|The C++ Standardization effort has not yet addressed these issues, to my
|knowledge. My only hope is that they don't neglect to address these
|issues, nor that they do worse than ANSI/ISO C. I'd prefer that they
|adopt much of the language of the C Standard re sequence points, constraints,
|etc wholesale. However, if they 'just' continue to follow the ARM document
|format, this may not happen.
Thank you, I got about sequence points. It seems though that ANSI C set
of sequence points does not lovely enough interact with INLINING
and OPERATOR OVERLOADING. Consider:
int i=0, *p=&i;
inline void g(int& r) {i=r++; cout << "g(i): r=" << r << endl;}
inline void f(int n) {i=n;};
main() { cout << (i=i++) << ' ' << f(i) << ' ' << f(*p) << endl;
i=i++;
cout << "i=0;i=i++; : " << i << endl;
g(i);
}
Borland (version 1.0 for OS/2 2.0) gives
0 0
i=0;i=i++; : 1
g(i): r=2
So, Borland is faultless here but both compiler and user must distinguish
between f() and g() situations.
Equally unfair is a situation of migrating from built-in to user type:
consider
class Int { int i;
public: Int(int n):i(n){}
operator int&() {return i;}
}; // class Int : public int {}; would be more natural :-(
and substitute int by Int everywhere in previous example; result should
change to all zeroes (formally, Int::operator=() is generated by compiler).
Maybe, it is worth to introduce new sequence point between operands
and operator execution? No compatibility problems (that is why language
designers are so fond of undefined behaviour :-) ). Seems, code generation
actually will be touched only for ++ and -- , guess, only postfix ones.
Well, for some machines and constructions
such as `*p=i++' it could result in less efficient code, but for static
or more static left side as `a[i]=b[j]++' a compiler could do as ever
because it knows that `a' and `b' are in different memory.
Resume: the question is too minor to struggle for this or that
but personally I would add a bit of clarity by the cost
of a bit of efficiency. The main achievment would be the ability
to say that in C++ functions and operations are two syntaxes
for single notion.
- Alex (Alexander Gootman, Novosibirsk, Russia)
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Sat, 13 Nov 1993 09:27:09 GMT Raw View
Alexander Gootman <gtm@cer.nsk.su> writes:
>Thank you, I got about sequence points. It seems though that ANSI C set
>of sequence points does not lovely enough interact with INLINING
>and OPERATOR OVERLOADING. Consider:
"inline" is a compiler hint.
It should not have any effect on sequence points or order of evalution.
Operator overloading doesn't have anything to do with order of evaluation.
>int i=0, *p=&i;
>inline void g(int& r) {i=r++; cout << "g(i): r=" << r << endl;}
>inline void f(int n) {i=n;};
>main() { cout << (i=i++) << ' ' << f(i) << ' ' << f(*p) << endl;
> i=i++;
> cout << "i=0;i=i++; : " << i << endl;
> g(i);
>}
I'm completely mystified by this example. What point are you
trying to make here?
--
Fergus Henderson fjh@munta.cs.mu.OZ.AU
Author: kanze@us-es.sel.de (James Kanze)
Date: 15 Nov 93 15:08:56 Raw View
In article <9331720.1111@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU
(Fergus Henderson) writes:
|> Operator overloading doesn't have anything to do with order of evaluation.
Except that an overloaded operator is a function call. As such, it
introduces a sequence point, ie: the i=i++ is undefined for basic
types like integer, but well behaved with overloaded operators, since
the side effects of evaluating the arguments to function operator=
must take place *before* the function call. (Supposing, of course,
that the C++ standards committee finally adapts the notion of sequence
points from the C standard.)
Another distinction occurs with operator|| and operator&&. For
built-in types, these operators short circuit, ie: if the results are
determined by the left argument, the right argument is not even
evaluated. For the user overloaded versions, however, both arguments
are always evaluated.
--
James Kanze email: kanze@us-es.sel.de
GABI Software, Sarl., 8 rue du Faisan, F-67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung