Topic: ++var
Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/10/15 Raw View
On 14 Oct 99 07:55:46 GMT, Christopher Eltschka
<celtschk@physik.tu-muenchen.de> wrote:
Your model is too permissive. The standard is more restrictive.
: Now in this implementation, each single sequence consists of
: the code of one processor, and each wait denotes a sequence
: point.
: And now look what would happen in this implementation if
: given the code
:
: f(g(i++), h(i--))
:
: The first processor would instruct the second processor to
: evaluate g(i++) and the third processor to evaluate h(i--),
: then wait for both to finish.
No, that is not allowed. G and h must not be executed in
parallel nor may either execute in parallel with the calling
code. The expressions i++ and i-- may be executable in
parallel, I'm not sure. But they may not be executed in
parallel with either g or h. The sequence point at function
call applies to all computations.
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: phalpern@newview.org (Pablo Halpern)
Date: 1999/10/14 Raw View
"David J. Littleboy" <davidjl@gol.com> wrote:
>Ron Natalie wrote in message <37FF9210.A174BDF3@sensor.com>...
>>>
>>Have you been reading this thread? As many of us have pointed out,
>>the fact that their is a sequence point at the call to the operator<<
>>function doesn't help. Both of the expressions involving i can be
>>evaluated before the op<< functions are called, making the expression
>>behavior undefined.
I actually missed another branch of this thread because of a goof on my
part in using the newsreader. Sorry for the repetition. I did find the
other part eventually.
>For those of us who didn't see this immediately, here's a painfully detailed
>explanation.
>
>The _reason_ the two expressions involving i can be evaluated in any order
>is that the operator<<() function is a function of _two_ arguments, a stream
>and the thing to print, and the compiler is allowed to evaluate arguments to
>functions in any order. Furthermore,
>
>cout << i << ++i;
>
>really looks like
>
>operator<<( operator<<(cout, i) , ++i);
Oooooh! This is what I've been missing. I forgot that a.f(b) is really
the same as f(this = &a, b). I had been assuming that a.f(b).f(c)
imposed a sequence point and ordering between the evaluations of b and
c. Rewriting this as f(f(a, b), c) shows me that c does not necessarily
come after b in the evaluation order.
Thanks.
-------------------------------------------------------------
Pablo Halpern phalpern@newview.org
I am self-employed. Therefore, my opinions *do* represent
those of my employer.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/10/14 Raw View
Pablo Halpern wrote:
[...]
> But how is this different from the function sequence points where you
> state that "the sequence points here do not impact that the ++i and --i
> are arguments to functions and distinct from the calls"? It seems to me
> that in both the above case and in the case of operator<< that ++i and
> --i are arguments to *different* function calls and that there is a
> sequence point *between* the function calls. What am I missing?
I think the problem is that the term "sequence point" makes one
think of a single sequence for the whole evaluation, with
sequence points on the way.
Indeed the reality is that there are multiple sequences, and a
sequence point is only relevant for the sequence it appears in.
For example, the "function call" sequence is:
evaluate arguments . execute function body
(where "." denotes the sequence point)
As you see, there's no sequence point in the "evaluate arguments"
part, which could separate both arguments.
Now, each single argument can be a sequence on its own, f.ex.
because it's a function call as well. However, this doesn't
affect the sequence of the outer function call: Sequence points
of subexpressions are _not_ sequence points of the expression.
Imagine a multiprocessor machine with a compiler that gives
separate processors the task of evaluating different arguments.
The "function call" code would look like this:
for each argument:
assign argument evaluation to other processor
wait until all processors gave "finished evaluation" signal
execute function body
set return value
send "finished evaluation" signal to invoking processor
The "operator&&" code could then look like this:
assign first subexpression evaluation to other processor
wait for "finished evaluation"
if result is true:
set return value to true
else:
assign second subexpression evaluation to other processor
wait for "finished evaluation"
set return value to result
send "finished evaluation"
Now in this implementation, each single sequence consists of
the code of one processor, and each wait denotes a sequence
point.
And now look what would happen in this implementation if
given the code
f(g(i++), h(i--))
The first processor would instruct the second processor to
evaluate g(i++) and the third processor to evaluate h(i--),
then wait for both to finish.
The second processor would ask The third processor would ask
the fourth processor to the fifth processor to
evaluate i++, and then wait for evaluate i-- and then wait for
it to finish it to finish
The fourth processor would read The fifth processor would read
i, increment the value, store it i, decrement the value, store it
back, set the return value and back, set the return value and
finish finish
The second processor would call The third processor would call
g, set the return value and finish h, set the return value and finish
The first processor would call f, set the return value and finish
As you see, there are five sequences evaluated, but since
sequences 2 and 3 have to wait for 4 resp. 5, one can consider
it as 3 sequences: The whole one, and the two running in parallel.
Now as you see, both sequences access i, and there's no way to know
what exactly will happen to i (it depends on if S4 or S5 is
reached first, or if they are even concurrent).
Now if f.ex. one sequence writes i while the other one is
just reading it, anything could happen. For example, the
system could be designed to just trap in that case (on the
philosophy that it's the program's task to protect concurrent
accesses f.ex. with lock instructions - which will certainly
not be done unless necessary).
This view of sequences as independant threads and sequence
points as waits for child threads allows one to identify
all sequence point related undefined behaviour to parallel
threads concurrently writing, or some writing and some
reading.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "David J. Littleboy" <davidjl@gol.com>
Date: 1999/10/10 Raw View
Ron Natalie wrote in message <37FF9210.A174BDF3@sensor.com>...
>>
>Have you been reading this thread? As many of us have pointed out,
>the fact that their is a sequence point at the call to the operator<<
>function doesn't help. Both of the expressions involving i can be
>evaluated before the op<< functions are called, making the expression
>behavior undefined.
For those of us who didn't see this immediately, here's a painfully detailed
explanation.
The _reason_ the two expressions involving i can be evaluated in any order
is that the operator<<() function is a function of _two_ arguments, a stream
and the thing to print, and the compiler is allowed to evaluate arguments to
functions in any order. Furthermore,
cout << i << ++i;
really looks like
operator<<( operator<<(cout, i) , ++i);
Since i and ++i appear in different arguments to the outer operator<<(), the
compiler gets to reorder them as it pleases, and the side effects in one
argument to an object that is evaluated in the other argument make the
behavior undefined.
David J. Littleboy
Tokyo, Japan
davidjl <at> gol <dot> com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: phalpern@newview.org (Pablo Halpern)
Date: 1999/10/11 Raw View
jpotter@falcon.lhup.edu (John Potter) wrote:
>On 09 Oct 99 04:44:19 GMT, phalpern@newview.org (Pablo Halpern) wrote:
>: This is different from
>: something you posted in a different branch of this thread:
>:
>: f(++i) + g(--i)
>:
>: In this case, allthough there are sequence points before and after the
>: calls to f() and g(), the order of these sequence points is not defined
>: in the standard. I consider the output expression in the original
>: posting to be closer to the f(g(++i)) case.
>
>You have the case you need. Now consider that a user defined operator+
>and the results are the same.
>
> operator+(f(++i), g(--i));
>
>All parameters to all functions may be evaluated in any order.
David Littleboy also pointed this out to me. Even in the case of a
member function, the "this" value is a separate parameter to the
function and can be evaluated in any order wrt the other parameters.
This was the source of my confusion. I knew that "this" was a function
parameter, but somehow forgot about that in this context. To rephrase,
if operator+ were a user-defined *member* function, then the above would
be:
f(++i).operator+(g(--i))
This gives the false impression that f(++i) must be evaluated first.
Rewriting it as:
opertor+([this = f(++i)], g(--i))
Shows that the evaluations of ++i and --i have no ordering requirement
and have no sequence point between them. This helps a lot.
>: What about this:
>:
>: int f(int);
>: f(++i) && f(--i);
>Builtin && introduces a sequence point and is not a function with two
>parameters which may be evaluated prior to calling it.
Oh right. I got too caught up in thinking about function sequence points
to realize that this was not one of them.
I understand this issue now. I even know how to explain it to other
people. Thanks for everybody's help.
P.S. I would never have written questionable code like the post that
started this thread, but it's nice to get the deeper understanding of
the issue anyway.
-------------------------------------------------------------
Pablo Halpern phalpern@newview.org
I am self-employed. Therefore, my opinions *do* represent
those of my employer.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: phalpern@newview.org (Pablo Halpern)
Date: 1999/10/09 Raw View
"Ken Hagan" <K.Hagan@thermoteknix.co.uk> wrote:
>The second statement is undefined, since "<<" is not an operator
>which has a sequence point. (Actually, I don'y think any _overloaded_
>operator has a sequence point, but no doubt someone will correct
>me if I'm wrong.) In the absence of that sequence point, the compiler
>is free to evaluate both "++i" and "--i" in pseudo parallel -- that is,
>it can load the starting value of i into two registers, decrement one
>and increment the other, and write them back in either order. You
>might find it interesting to insert "cerr << i << endl;" after each of
>the three examples.
I think the opposite is true. Overloaded operators are functions and
there is a sequence point before and after every function call. It seems
to me that both the first and second statements are well-defined and
should yield the sequence 6 5 6 5 ??, where the ?? is the undefined
value produced by the third output statement.
What makes me uneasy is that A) the egcs compiler seems to have done the
wrong thing under Linux and B) this thread has been going on for a long
time and nobody pointed out that the second statement is well-defined
and should produce the same results on all compilers. This makes me
wonder if I'm missing something.
-------------------------------------------------------------
Pablo Halpern phalpern@newview.org
I am self-employed. Therefore, my opinions *do* represent
those of my employer.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: phalpern@newview.org (Pablo Halpern)
Date: 1999/10/09 Raw View
comeau@panix.com (Greg Comeau) wrote:
>In article <7savq1$qbg2@interserv.etn.com> "Ed Brey" <brey@afd.mke.etn.com> writes:
>>cout.operator<<(++i).operator<<(endl).operator<<(--i).operator<<(endl);
>>....
>>Clearly operator<<(++i) must be evaluated before
>>operator<<(--i), because operator<<(--i) needs the results of
>>operator<<(++i) for its this pointer.
>
>Yes, but...
>
>>The question is does this ordering
>>force the --i to have to be evaluated before the ++i?
>
>.... I don't see why. The sequence points here do not impact that the
>++i and --i are arguments to functions and distinct from the calls and
> . operators
So what? Doesn't the definition of a sequence point say that *all*
side-effects must be completed? By that definition, shouldn't the ++i
side-effect have to be complete before the first call to operator<<()?
I must admit, even as a professed C/C++ expert that sequence points at
function calls have long mystified me. An statement like
expr1 && expr2 && expr3;
is easy to figure out. The sequence points occur left-to-right. Now how
about:
f(g(++i));
I would understand this to mean that there is a sequence point before
calling g(), after returning from g(), before calling f() and after
returning from f(). I would also assume that that g() must be called
before f(), thus imposing an ordering on the sequence points (hmm... Is
that right?). If i is a global, can f() assume that it has its new
value? Can g() make the same assumption? This is different from
something you posted in a different branch of this thread:
f(++i) + g(--i)
In this case, allthough there are sequence points before and after the
calls to f() and g(), the order of these sequence points is not defined
in the standard. I consider the output expression in the original
posting to be closer to the f(g(++i)) case.
What about this:
int f(int);
f(++i) && f(--i);
If I understand correctly, above is exactly the same as:
int f(int);
if (f(++i))
f(--i);
But how is this different from the function sequence points where you
state that "the sequence points here do not impact that the ++i and --i
are arguments to functions and distinct from the calls"? It seems to me
that in both the above case and in the case of operator<< that ++i and
--i are arguments to *different* function calls and that there is a
sequence point *between* the function calls. What am I missing?
I'm struggling to articulate the exact nature of my confusion but, at
this point, I feel like writing any more would only be making things
more confusing. I hope you all can figure out what I'm trying to ask.
-------------------------------------------------------------
Pablo Halpern phalpern@newview.org
I am self-employed. Therefore, my opinions *do* represent
those of my employer.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: 1999/10/09 Raw View
Dirk van Deun wrote:
....
> int i = 5;
> cerr << ++i << endl, cerr << --i << endl;
> i = 5;
> cerr << ++i << endl << --i << endl;
> i = 5;
> cerr << ++i + --i << endl;
Pablo Halpern wrote:
>
> "Ken Hagan" <K.Hagan@thermoteknix.co.uk> wrote:
....
> I think the opposite is true. Overloaded operators are functions and
> there is a sequence point before and after every function call. It seems
You are correct about this. However, in two of the statements both ++i
and --i can be evaluated before the first function call, so the sequence
points don't help.
> to me that both the first and second statements are well-defined and
> should yield the sequence 6 5 6 5 ??, where the ?? is the undefined
> value produced by the third output statement.
I think you're mis-counting the statements. The first, third, and fifth
statements produce no output. The second one would normally produce "6
5", and nothing more. The fourth one is undefined, because the compiler
is free to rearrange the order of evaluation so that the ++i and the --i
both occur, in either order, before the first function call. It's not
just that you don't know which of the two will execute first. Two writes
to the same variable without an intervening sequence point is undefined
behavior.
The sixth statement is the worst, because even the most natural way of
ordering it results in two writes without an intervening sequence point.
Because the behavior of the program as a whole is undefined, any
statement in it can fail, not just the ones that make it undefined.
Therefore you can't even predict the output of the second statement,
which was in itself perfectly acceptable.
> What makes me uneasy is that A) the egcs compiler seems to have done the
> wrong thing under Linux and B) this thread has been going on for a long
> time and nobody pointed out that the second statement is well-defined
> and should produce the same results on all compilers. This makes me
> wonder if I'm missing something.
The second statement is indeed well-defined, but judging from the above
I believe that you're actually thinking about the fourth statement,
which isn't. If you think it is, you have missed something. This has
already been thoroughly covered in the other messages on this thread.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/10/09 Raw View
On 09 Oct 99 04:43:57 GMT, phalpern@newview.org (Pablo Halpern) wrote:
: "Ken Hagan" <K.Hagan@thermoteknix.co.uk> wrote:
:
: >The second statement is undefined, since "<<" is not an operator
: >which has a sequence point. (Actually, I don'y think any _overloaded_
: >operator has a sequence point, but no doubt someone will correct
: >me if I'm wrong.)
Yes, you are wrong. User overloaded operators are functions which
introduce two sequence points.
: In the absence of that sequence point, the compiler
: >is free to evaluate both "++i" and "--i" in pseudo parallel -- that is,
: >it can load the starting value of i into two registers, decrement one
: >and increment the other, and write them back in either order. You
: >might find it interesting to insert "cerr << i << endl;" after each of
: >the three examples.
It is still undefined because the sequence points are not between the
two evaluations.
: I think the opposite is true. Overloaded operators are functions and
: there is a sequence point before and after every function call.
Yes.
: It seems
: to me that both the first and second statements are well-defined and
: should yield the sequence 6 5 6 5 ??, where the ?? is the undefined
: value produced by the third output statement.
No.
: What makes me uneasy is that A) the egcs compiler seems to have done the
: wrong thing under Linux
Anything is right when it is undefined.
: and B) this thread has been going on for a long
: time and nobody pointed out that the second statement is well-defined
: and should produce the same results on all compilers. This makes me
: wonder if I'm missing something.
I have tried, but here goes again.
The second statement
i = 5;
cerr << ++i << endl << --i << endl;
Will you accept that the endl is immaterial to this point?
cerr << ++i << --i;
With member functions, this is
cerr.operator<<(++i).operator<<(--i);
With non-member functions, this is
operator<<(operator<<(++i), --i);
Order of evaluation of parameters is unspecified; therefor, it is
valid to evaluate ++i and --i in either order prior to any call of
the two functions. The result is storing to i twice without a
sequence point. Since these are two of the valid evaluations, the
behavior is undefined.
++i; --i; cerr << i; cerr << i;
--i; ++i; cerr << i; cerr << i;
++i; cerr << i; --i; cerr << i;
You want the last, but the other two are valid. Correct behavior
could be 6 5 coredump. And of course, since there is undefined
behavior, no output coredump, or nothing at all would also be
correct.
John
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/10/09 Raw View
phalpern@newview.org (Pablo Halpern) writes:
>So what? Doesn't the definition of a sequence point say that *all*
>side-effects must be completed?
The side effects of the associated expression must be complete,
not all side effects. What constitutes an associated expresion
(my terminology, not the standard's) is defined for each
sequence point. In general, sequence points impose a partial
ordering, not necessarily a total ordering.
For a function call, one sequence point is between evaluating
the function arguments and calling the function. The other
is between copying out the return value and evaluation of
other parts of the expression in which the call appears.
>I must admit, even as a professed C/C++ expert that sequence points at
>function calls have long mystified me. An statement like
> expr1 && expr2 && expr3;
>is easy to figure out. The sequence points occur left-to-right.
Right, because the definition of && says the there is a sequence
point after evaluating the left side, and that the right side is
not evaluated if the left side evalutes to 'true'. All side
effects of the left side must be complete before the right
side or any of its side effects can be evaluated.
>Now how about:
> f(g(++i));
>I would understand this to mean that there is a sequence point before
>calling g(), after returning from g(), before calling f() and after
>returning from f().
Sort of. There is no sequence point as such after returning from
a function. The sequence point occurs between copying out the
return value and evaluating other parts of the calling expression.
For example, if the return value is stored in a temp, the temp has
its final value before the remainder of the calling expression
can access it.
>I would also assume that that g() must be called
>before f(), thus imposing an ordering on the sequence points (hmm... Is
>that right?).
In this case, yes. You can't enter g until ++i is complete, and
you can't call f until its argument is evaluated.
>If i is a global, can f() assume that it has its new
>value? Can g() make the same assumption?
Yes to both, for the above reasons.
>This is different from
>something posted in a different branch of this thread:
> f(++i) + g(--i)
>In this case, allthough there are sequence points before and after the
>calls to f() and g(), the order of these sequence points is not defined
>in the standard.
The only requirements are
++i must be completed before f is called
--i must be completed before g is called
That's all we know. Allowable sequences include
++i f --i g
--i g ++i f
++i --i f g
++i --i g f
--i ++i f g
--i ++i g f
Since there is no sequence point *separating* ++i from --i,
the result of the entire expression is undefined.
--
Steve Clamage, stephen.clamage@sun.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/10/10 Raw View
In article <38006778.357291518@news.internetconnect.net>, Pablo Halpern
<phalpern@newview.org> writes
>But how is this different from the function sequence points where you
>state that "the sequence points here do not impact that the ++i and --i
>are arguments to functions and distinct from the calls"? It seems to me
>that in both the above case and in the case of operator<< that ++i and
>--i are arguments to *different* function calls and that there is a
>sequence point *between* the function calls. What am I missing?
>
>I'm struggling to articulate the exact nature of my confusion but, at
>this point, I feel like writing any more would only be making things
>more confusing. I hope you all can figure out what I'm trying to ask.
Nested function calls are a red herring. The point is that the compiler
is free to evaluate the arguments of all the functions in a complete
expression before it calls any of the functions. The existence of
sequence points at function call and function return do nothing to help
with this problem. (The purpose of those s.p. are to insulate the body
of a function from side effects resulting from the evaluation of its
arguments, and the calling code from the side effects of evaluating the
body of the function.
Many people find s.p. confusing because they want to read them from left
to right. Try thinking of them as places that insulate some code from
the effects of some other code.
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/10/10 Raw View
On 09 Oct 99 04:44:19 GMT, phalpern@newview.org (Pablo Halpern) wrote:
: f(g(++i));
:
: I would understand this to mean that there is a sequence point before
: calling g(), after returning from g(), before calling f() and after
: returning from f(). I would also assume that that g() must be called
: before f(), thus imposing an ordering on the sequence points (hmm... Is
: that right?). If i is a global, can f() assume that it has its new
: value? Can g() make the same assumption?
Yes to everything.
: This is different from
: something you posted in a different branch of this thread:
:
: f(++i) + g(--i)
:
: In this case, allthough there are sequence points before and after the
: calls to f() and g(), the order of these sequence points is not defined
: in the standard. I consider the output expression in the original
: posting to be closer to the f(g(++i)) case.
You have the case you need. Now consider that a user defined operator+
and the results are the same.
operator+(f(++i), g(--i));
All parameters to all functions may be evaluated in any order.
: What about this:
:
: int f(int);
: f(++i) && f(--i);
:
: If I understand correctly, above is exactly the same as:
:
: int f(int);
: if (f(++i))
: f(--i);
:
: But how is this different from the function sequence points where you
: state that "the sequence points here do not impact that the ++i and --i
: are arguments to functions and distinct from the calls"? It seems to me
: that in both the above case and in the case of operator<< that ++i and
: --i are arguments to *different* function calls and that there is a
: sequence point *between* the function calls. What am I missing?
Builtin && introduces a sequence point and is not a function with two
parameters which may be evaluated prior to calling it. One good
reason to never overload operator&&. An overloaded operator&& is a
function and does not introduce a sequence point between evaluation
of its parameters.
Back to the first one.
f(g(++i))
is well defined, but
f(g(++i, --i))
or
f(g(++i), --i)
are not.
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 1999/10/10 Raw View
Pablo Halpern wrote:
>
> I think the opposite is true. Overloaded operators are functions and
> there is a sequence point before and after every function call. It seems
> to me that both the first and second statements are well-defined and
> should yield the sequence 6 5 6 5 ??, where the ?? is the undefined
> value produced by the third output statement.
>
Have you been reading this thread? As many of us have pointed out,
the fact that their is a sequence point at the call to the operator<<
function doesn't help. Both of the expressions involving i can be
evaluated before the op<< functions are called, making the expression
behavior undefined.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 1999/10/04 Raw View
"David J. Littleboy" wrote:
>
> Francis Glassborow wrote in message
> <75aLitAEpK63EwwC@robinton.demon.co.uk>...
> >>i = 5;
> >>cerr << i << endl << --i << endl;
1 2
>
> Doesn't operator<<() introduce sequence points here? I thought overloaded
> operators introduced sequence points, as in footnote 12, page 8?????
>
It introduces sequence points, but not at a place that does any good.
The value i (at #1 above) and --i (at #2) may both be evaluated prior
to any of the operator<< functions being called (which would be sequence
points).
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 1999/10/01 Raw View
AllanW wrote:
> This doesn't modify any object twice. Unless operator++ does
> something very strange, this is equivalent to
> ++i;
> *i=c;
But it may be:
load i into temporary register
increment temporary register
store c into the address in the temporary register
store the temporary register into i.
You see, without a sequence point you don't know if i will
have the new value before or after c is stored.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jcoffin@taeus.com (Jerry Coffin)
Date: 1999/10/01 Raw View
In article <7speoe$eal$1@nnrp1.deja.com>, allan_w@my-deja.com says...
[ ... ]
> Undefined programs *ARE* errors.
This is simply NOT true. Code that's not defined by the standard may
well still be completely error-free. The code probably isn't
portable, but that's an entirely different question.
Unlike Java, both C and C++ not only allow but endorse the idea of
writing code that's not portable. For example, somebody writing a
device driver might well take some integer and cast it to a pointer,
allowing them to do I/O to/from a memory-mapped device. The result of
this is clearly undefined under the standard, but on their particular
implementation does exactly what they want.
--
Later,
Jerry.
The universe is a figment of its own imagination.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James Kuyper <kuyper@wizard.net>
Date: 1999/10/01 Raw View
Ron Natalie wrote:
>
> AllanW wrote:
>
[Re: *++i=c;]
> > This doesn't modify any object twice. Unless operator++ does
> > something very strange, this is equivalent to
> > ++i;
> > *i=c;
>
> But it may be:
>
> load i into temporary register
> increment temporary register
> store c into the address in the temporary register
store c into the location who's address is in the temporary register.
> store the temporary register into i.
>
> You see, without a sequence point you don't know if i will
> have the new value before or after c is stored.
So? what does it matter (unless c is a reference to i, or similar
complications, which were not specified)?
No matter what order it's done in,
1. '*i', for the original value of 'i', remains unchanged
2. 'i' increases by 1
3. '*i' for the final value of 'i' contains the value of 'c'.
It really doesn't matter which of those two changes happens first.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: AllanW <allan_w@my-deja.com>
Date: 1999/09/30 Raw View
In article <t7671458e5.fsf@calumny.jyacc.com>,
Hyman Rosen <hymie@prolifics.com> wrote:
> sbnaran@uiuc.edu (Siemel B. Naran) writes:
> > So '*' is a sequence point?
>
> No, of course not. What are you so confused about? The expression ++p
> causes p to be incremented, and its value is the incremented value, so
> *++p addresses what the incremenetd pointer points at, just as if you
> had written p[1]. You are assured that the actual modification of p
> has happened when you encounter the next sequence point. OK?
To say this another way:
The order of operations determines WHAT will happen.
In *++i=c, the ++i happens before the *, so we dereference
the incremented value of i.
The sequence-point rules determine WHEN it will happen.
In *++i=c, the variable i might be updated before the
dereferenced element is assigned the value of c, or
it might happen afterwords. But it *WILL* happen.
The rule that says something can only be modified once is
required to keep things sane. Otherwise, if c and i happen
to refer to the same variable, there's no way to know what
the result will be. Remember, we don't know when i will be
updated, so using that result before the next sequence
point is a big problem.
--
Allan_W@my-deja.com is a "Spam Magnet," never read.
Please reply in newsgroups only, sorry.
Sent via Deja.com http://www.deja.com/
Before you buy.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: AllanW <allan_w@my-deja.com>
Date: 1999/10/01 Raw View
In article <37F4DF1E.FBD81A85@sensor.com>,
Ron Natalie <ron@sensor.com> wrote:
>
>
> AllanW wrote:
>
> > This doesn't modify any object twice. Unless operator++ does
> > something very strange, this is equivalent to
> > ++i;
> > *i=c;
>
> But it may be:
>
> load i into temporary register
> increment temporary register
> store c into the address in the temporary register
> store the temporary register into i.
>
> You see, without a sequence point you don't know if i will
> have the new value before or after c is stored.
That was one of my points! (I did have a point, honest!)
Again: the "operator precedence" determines WHAT will happen.
The rules about side effects determine WHEN they will happen.
These shouldn't be confused.
The rules about side effects say that i might be updated
before the value of c is stored, or afterwards. But the rules
about operator precedence say that the place where c's value
is stored, is at the address that i ends up pointing to, not
the one it originally pointed to.
--
Allan_W@my-deja.com is a "Spam Magnet," never read.
Please reply in newsgroups only, sorry.
Sent via Deja.com http://www.deja.com/
Before you buy.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "David J. Littleboy" <davidjl@gol.com>
Date: 1999/10/02 Raw View
Francis Glassborow wrote in message
<75aLitAEpK63EwwC@robinton.demon.co.uk>...
>>i = 5;
>>cerr << i << endl << --i << endl;
>>
>>Is it undefined, and, if not, why not?
>
>It is (undefined) because the full rule requires that any access to the
>value of an object that is to be written to between sequence points
>shall be for the purpose of determining the value to be written. The
>first use of i in the above breeches this constraint.
Doesn't operator<<() introduce sequence points here? I thought overloaded
operators introduced sequence points, as in footnote 12, page 8?????
Obviously,
int c, i = 7;
c = 13 + i + 17 + --i + 19;
is problematic. (I think.)
David J. Littleboy
Tokyo, Japan
davidjl <at> gol <dot> com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/10/02 Raw View
On 2 Oct 1999 15:47:53 GMT, "David J. Littleboy" <davidjl@gol.com>
wrote:
: Francis Glassborow wrote in message
: <75aLitAEpK63EwwC@robinton.demon.co.uk>...
: >>i = 5;
: >>cerr << i << endl << --i << endl;
: >>
: >>Is it undefined, and, if not, why not?
: >
: >It is (undefined) because the full rule requires that any access to the
: >value of an object that is to be written to between sequence points
: >shall be for the purpose of determining the value to be written. The
: >first use of i in the above breeches this constraint.
:
: Doesn't operator<<() introduce sequence points here? I thought overloaded
: operators introduced sequence points, as in footnote 12, page 8?????
Yes it introduces sequence points, but they are not between the two
evaluations of i. The above looks like:
f(f(c, i), --i);
The parameters may be evaluated prior to any call; thus, without an
interveining sequence point.
John
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/10/03 Raw View
In article <IOeJ3.576$a7.75647@nnrp.gol.com>, David J. Littleboy
<davidjl@gol.com> writes
>Francis Glassborow wrote in message
><75aLitAEpK63EwwC@robinton.demon.co.uk>...
>>>i = 5;
>>>cerr << i << endl << --i << endl;
>>>
>>>Is it undefined, and, if not, why not?
>>
>>It is (undefined) because the full rule requires that any access to the
>>value of an object that is to be written to between sequence points
>>shall be for the purpose of determining the value to be written. The
>>first use of i in the above breeches this constraint.
>
>Doesn't operator<<() introduce sequence points here? I thought overloaded
>operators introduced sequence points, as in footnote 12, page 8?????
It does, but too late to help. The arguments (i and --i) can both be
evaluated before any function is called.
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: AllanW <allan_w@my-deja.com>
Date: 1999/09/30 Raw View
In article <37E2880B.59AE0EAD@ix.netcom.com>,
cut-m.austin@ix.netcom.com wrote:
>
> If it's undefined, shouldn't it be an error???
Undefined programs *ARE* errors. However, the compiler is
not required to diagnose this particular error; it can
instead generate code which does anything at all (including
what you expect).
Requiring the compiler to diagnose every possible error that
any programmer can make, is simply beyond reason.
--
Allan_W@my-deja.com is a "Spam Magnet," never read.
Please reply in newsgroups only, sorry.
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: 1999/09/28 Raw View
Hyman Rosen wrote:
>
> James Kuyper <kuyper@wizard.net> writes:
> > Hyman Rosen wrote:
> > > If you never invoke the generated program, then how do you know whether
> > > the compiler refused to compile it? :-)
> > At least one diagnostic is required, if it chooses to refuse to compile
> > it for this reason.
>
> Sure, but the compiler could say
>
> kuyper.cpp: 10: Division by zero.
>
> This is a perfectly reasonable diagnostic, but it doesn't tell you
> whether the compiler chose to give you an executable.
The only thing the standard guarantees about diagnostics is that if your
program is translated and executed by a conforming implementation
without producing any diagnostics, it has no problems that require a
diagnostic. Everything else is QoI.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/09/28 Raw View
In article <37eb4d85.60150804@news.csrlink.net>,
jpotter@falcon.lhup.edu (John Potter) wrote:
> On 24 Sep 99 07:26:05 GMT, James.Kanze@dresdner-bank.com wrote:
>
> : In article <37e810ad.18856802@news.csrlink.net>,
> : jpotter@falcon.lhup.edu (John Potter) wrote:
>
> : > Let's
> : > prove it with an absurdity which also covers assignment and its
> : > lvalue.
> :
> : > int i[2];
> : > int* p(i);
> : > int** pp;
> : > int*** ppp;
> : > ***(ppp = &(pp = &++p)) = 5;
> : > Sure enough, all of the variables have the expected values, but
the
> : > code is:
> : > int* reg = p + 1;
> : > *reg = 5;
> : > ppp = &pp;
> : > pp = &p
> : > p = reg;
> : The original expression contains undefined behavior, see 5/4: "Between
> : the previous and next sequence point a scalar 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." The above expression modifies both pp and ppp, and
> : accesses them as well other than to determine the value to be written in
> : the access.
> Sorry. The behavior is fine. It accesses the new not prior value
> of those variables.
Ooops. I'll admit I'm not too used to reading this kind of expression.
> The prior value is not used at all. It accesses
> the prior value of p to determine the new value only, but also
> accesses the new value of p which is not prohibited.
You mean, it calculates the new value of p, then uses it. As a side
effect, it also stores this value in p.
> You're not
> really trying to say that
> while ((ch = cin.get()) != EOF)
> has undefined behavior, are you?
No. But again, there is no sequence point, nor is one needed. The
results of an assignment expression is an lvalue (C++)/rvalue (C) with
the type of the left hand side of the expression and the value of the
right hand side. In C++, the lvalue object is also the left hand side.
Lets make a real example, where you can observe the difference:
volatile int ch ;
volatile bool eofSeen ;
while ( eof = ((ch = cin.get()) != EOF) ) ...
Since both variables are volatile, there modification is an observable
behavior. The standard, however, makes no guarantee concerning the
order in which they will be written. Neither the C standard, nor the
C++ standard.
> Maybe you see my point. These
> operators which return an lvalue in C++ refer to the variable and
> it must have the new value.
No. Operators which return an lvalue in C++ have the value and type of
the expression; as an lvalue, they refer to the object, but there is no
requirement that the side effect of modifying the lvalue occur before
the next sequence point. The only guarantee I can find is in 1.8/7: "At
certain specified points in the execution sequence called sequence
points, all side effects of previous evaluations shall be complete and
no side effects of subsequent evaluations shall have taken place."
Can you show me any further guarantee?
> Sequence points and as-if require a
> bit more hand waving than in C.
Only if user defined classes are involved. But then, you have a
function call, which implies a sequence point, and we are off the
hook:-).
Actually, it could be clearer. The semantics of assignment are that the
"result of the assignment operation is the value stored in the left
operand after the assignment has taken place." Which certainly seems to
imply some temporal ordering. The C standard goes on to explicitly say
that despite appearances, the ordering is *not* there. Historically, it
hasn't been there, and I don't think that the intent of the C++
committee was to add it.
> : > Totally ignored all of the semantics explained in the standard.
Let's
> : > try to catch them.
> : > int i[3];
> : > int* p(i);
> : > ++ ++ p;
> : > I didn't get the expected results, in fact I didn't get any output.
> : The
> : > code was:
> : > <self mail comp-std-c++@moderators.isc.org
> : > -s 'Look at the dumb thing I did'
> :
> : > Fortunately, it seems to have been lost along with my prior ramblings
> : > on this subject ;-)
> :
> : > That damned undefined behavior, I can't determine if ++p really
> : > returns an lvalue any other way. As-if rules!
> :
> : Sure you can.
> :
> : int i[2] ;
> : int* p( i ) ;
> : int*& pr = ++ p ;
> :
> : Only works if ++ p is an lvalue.
> The point is that the rvalue is the new value (p + 1) and the lvalue
> is p. There is no way to show that the rvalue of the returned lvalue
> is really the new value. You can use either of them, but not both in
> a way that shows that they are consistent. The sequence point
required
> to show consistency does not exist and falsehoods up to the next
> sequence point are allowed.
> : > So ++p returns the new value of p and *++p will work regardless of
> : > when the new value actually gets placed in p. C++ is a bit trickier
> : > than C because we get these lvalues which may not be lvalues that
> : > get converted to rvalues. In the absence of a sequence point, it
> : > can do whatever it wants as long as we can't tell.
> :
> : Correct. Even with sequence points, it can do whatever it wants as long
> : as we can't tell. Declaring the variables volatile, however, permits
> : observing their actual modification; i.e. we can tell.
> Can you demonstrate that the rvalue of the returned lvalue is the
> new value that way?
Try volatile variables. Of course, my implementation doesn't really
have any way of observing changes in volatile variables, so I can't
really tell either. But volatile variables are about the only way I
know of of observing behavior without a function call (which introduces
a sequence point).
> : > The bottom line is that the lvalues from prefix ++/-- and = are a
> : > crock of brown stuff other than allowing taking the address. Any
> : > other use is undefined behavior. > :
> : Any use of an lvalue presupposes in some way taking its address. Not in
> : the C++ sense (operator &), but in the physical sense. In the C++
> : sense, probably the most frequent use of this sort of lvalue-ness is not
> : taking the address, but binding the object to a reference. Binding an
> : lvalue to a reference means that the reference refers to that specific
> : object.
> But does not require that the rvalue of that object be correct at that
> point in time. The standard says that they return the new value and
> that it is an lvalue. It does not require that because there is no
> way to tell.
The C standard explicitly says that the actual value in the object is
not required to conform to the rvalue of the expression. I suspect that
the intent is for the same to hold for C++ -- there is nothing in the
standard which requires the abstract machine to actually read the lvalue
in order to obtain the rvalue, even when volatile variables are
involved.
--
James Kanze mailto: James.Kanze@dresdner-bank.com
Conseils en informatique orient e objet/
Beratung in objekt orientierter Datenverarbeitung
Ziegelh ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
Sent via Deja.com http://www.deja.com/
Before you buy.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Gabriel Dos_Reis <gdosreis@korrigan.inria.fr>
Date: 1999/09/29 Raw View
David R Tribble <david@tribble.com> writes:
[...]
| > 1.4/8
| > ---
| > ... Implementations are requiredd to diagnose programs that use such
| > extensions that are ill-formed according to this International
| > Standard. Havind done so, however, they can compile and execute
| > ^^^^^^^
| > such programs.
| > ---
| >
| > Was that an oversight?
|
| Even C++ interpreters have to "compile" the C++ source before (or
| at the point in time that) they attempt to execute/interpret it.
| A looser definition of "compile", then, seems to implied here,
| meaning something like "syntactically parse and semantically
| analyze".
Well, whereas the Standard unambiguously describes what it means to
translate a C++ program, it doesn't say anything about "to compile".
The Standardese equivalent was and is "to translate". Is there any
reason why the expression "to compile" suddenly appears in the
main normative text without further explanation?
--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/09/29 Raw View
On 28 Sep 1999 16:44:14 GMT, James.Kanze@dresdner-bank.com wrote:
: The C standard explicitly says that the actual value in the object is
: not required to conform to the rvalue of the expression. I suspect that
: the intent is for the same to hold for C++ -- there is nothing in the
: standard which requires the abstract machine to actually read the lvalue
: in order to obtain the rvalue, even when volatile variables are
: involved.
We actually agree :)
Being able to write **&++p = 5; does not mean that the new value has
been stored in p prior to anything ahead of the only sequence point,
but the 5 must be stored in the right place. Just a more complex
example of the original question that started this thread, *++p = 5;
Neither has undefined behavior, the semantics must be followed. The
fact that the store to p may be delayed does not change the fact that
the new value must be used in the calculation.
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/09/27 Raw View
"James Kuyper Jr." wrote:
>
> Barry Margolin wrote:
> ....
> > I don't think it has to go that far up the call tree to the shell. If you
> > never invoke the program, you wouldn't notice that the program was never
> > compiled, either, so it's safe for the compiler not to generate an
> > executable if it can determine that all paths from main() lead to undefined
> > behavior.
>
> Yes, but if either translation or execution is halted as a result, it
> must also generate a diagnostic. It could defer the message to run-time,
> by producing a program who's only real code prints the diagnostic.
But then it could also rely on the OS to produce that diagnostic -
it just has to document it:
"If the operating system refuses to run the resulting
executable (f.ex. because that executable doesn't exist),
it is considered a diagnostic of this compiler."
Not that I advocate this style of diagnostics ;-)
(BTW, what about: "If the program doesn't do what it is intended
to do, it is considered a diagnostic of the compiler."
Note that this allows the compiler to diagnose even errors
like
int main()
{
std::cerr << "Hello, world!" << std::endl;
// oops, should have been cout
}
since the non-intended behaviour - f.ex output to
fd 2 instead of fd 1 on Unix - is a diagnostic ;-))
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: David R Tribble <david@tribble.com>
Date: 1999/09/27 Raw View
Gabriel Dos_Reis wrote:
>
> Francis Glassborow <francis@robinton.demon.co.uk> writes:
>
> | James Kuyper <kuyper@wizard.net> writes
> | Well, I cannot find any requirement for code to be compiled.
> | AFAIK an implementation can be a pure interpreter.
>
> Well, I would bet ISO 14882 does not require a C++ implementation to
> be a compiler *but* I find the following in my copy:
>
> 1.4/8
> ---
> ... Implementations are requiredd to diagnose programs that use such
> extensions that are ill-formed according to this International
> Standard. Havind done so, however, they can compile and execute
> ^^^^^^^
> such programs.
> ---
>
> Was that an oversight?
Even C++ interpreters have to "compile" the C++ source before (or
at the point in time that) they attempt to execute/interpret it.
A looser definition of "compile", then, seems to implied here,
meaning something like "syntactically parse and semantically
analyze".
-- David R. Tribble, david@tribble.com --
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/09/27 Raw View
James Kuyper <kuyper@wizard.net> writes:
> Hyman Rosen wrote:
> > If you never invoke the generated program, then how do you know whether
> > the compiler refused to compile it? :-)
> At least one diagnostic is required, if it chooses to refuse to compile
> it for this reason.
Sure, but the compiler could say
kuyper.cpp: 10: Division by zero.
This is a perfectly reasonable diagnostic, but it doesn't tell you
whether the compiler chose to give you an executable.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: 1999/09/25 Raw View
Barry Margolin wrote:
....
> I don't think it has to go that far up the call tree to the shell. If you
> never invoke the program, you wouldn't notice that the program was never
> compiled, either, so it's safe for the compiler not to generate an
> executable if it can determine that all paths from main() lead to undefined
> behavior.
Yes, but if either translation or execution is halted as a result, it
must also generate a diagnostic. It could defer the message to run-time,
by producing a program who's only real code prints the diagnostic.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/09/25 Raw View
On 24 Sep 99 07:26:05 GMT, James.Kanze@dresdner-bank.com wrote:
: In article <37e810ad.18856802@news.csrlink.net>,
: jpotter@falcon.lhup.edu (John Potter) wrote:
: > Let's
: > prove it with an absurdity which also covers assignment and its
: > lvalue.
:
: > int i[2];
: > int* p(i);
: > int** pp;
: > int*** ppp;
: > ***(ppp = &(pp = &++p)) = 5;
: > Sure enough, all of the variables have the expected values, but the
: > code is:
: > int* reg = p + 1;
: > *reg = 5;
: > ppp = &pp;
: > pp = &p
: > p = reg;
:
: The original expression contains undefined behavior, see 5/4: "Between
: the previous and next sequence point a scalar 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." The above expression modifies both pp and ppp, and
: accesses them as well other than to determine the value to be written in
: the access.
Sorry. The behavior is fine. It accesses the new not prior value
of those variables. The prior value is not used at all. It accesses
the prior value of p to determine the new value only, but also
accesses the new value of p which is not prohibited. You're not
really trying to say that
while ((ch = cin.get()) != EOF)
has undefined behavior, are you? Maybe you see my point. These
operators which return an lvalue in C++ refer to the variable and
it must have the new value. Sequence points and as-if require a
bit more hand waving than in C.
: > Totally ignored all of the semantics explained in the standard. Let's
: > try to catch them.
: > int i[3];
: > int* p(i);
: > ++ ++ p;
: > I didn't get the expected results, in fact I didn't get any output.
: The
: > code was:
: > <self mail comp-std-c++@moderators.isc.org
: > -s 'Look at the dumb thing I did'
:
: > Fortunately, it seems to have been lost along with my prior ramblings
: > on this subject ;-)
:
: > That damned undefined behavior, I can't determine if ++p really
: > returns an lvalue any other way. As-if rules!
:
: Sure you can.
:
: int i[2] ;
: int* p( i ) ;
: int*& pr = ++ p ;
:
: Only works if ++ p is an lvalue.
The point is that the rvalue is the new value (p + 1) and the lvalue
is p. There is no way to show that the rvalue of the returned lvalue
is really the new value. You can use either of them, but not both in
a way that shows that they are consistent. The sequence point required
to show consistency does not exist and falsehoods up to the next
sequence point are allowed.
: > So ++p returns the new value of p and *++p will work regardless of
: > when the new value actually gets placed in p. C++ is a bit trickier
: > than C because we get these lvalues which may not be lvalues that
: > get converted to rvalues. In the absence of a sequence point, it
: > can do whatever it wants as long as we can't tell.
:
: Correct. Even with sequence points, it can do whatever it wants as long
: as we can't tell. Declaring the variables volatile, however, permits
: observing their actual modification; i.e. we can tell.
Can you demonstrate that the rvalue of the returned lvalue is the
new value that way?
: > The bottom line is that the lvalues from prefix ++/-- and = are a
: > crock of brown stuff other than allowing taking the address. Any
: > other use is undefined behavior.
:
: Any use of an lvalue presupposes in some way taking its address. Not in
: the C++ sense (operator &), but in the physical sense. In the C++
: sense, probably the most frequent use of this sort of lvalue-ness is not
: taking the address, but binding the object to a reference. Binding an
: lvalue to a reference means that the reference refers to that specific
: object.
But does not require that the rvalue of that object be correct at that
point in time. The standard says that they return the new value and
that it is an lvalue. It does not require that because there is no
way to tell.
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/09/25 Raw View
On 23 Sep 1999 18:08:08 GMT, "Ed Brey" <brey@afd.mke.etn.com> wrote:
:
: Ron Natalie <ron@sensor.com> wrote in message
: news:37E9388A.A4E769BB@sensor.com...
: >
: > It goes on to say: the prior value shall be accessed only to determine
: > the value to be stored.
:
: This requirement seems overly restrictive. For example, consider:
:
: if (i++);
:
: Here the prior value of b is accessed for two purposes: to determine the
: value to be stored into i, and to determine whether the if's expression is
: true (via implicit cast to bool). Therefore, the expression seems to
: violate the requirement, since the prior value is accessed in a way other
: than what is allowed.
The key word is "b". The prior value of b is *accessed* only once. It
is used to compute the new value of b and it is returned by the
operation. There is only one _read_ of b. The if tests the unnamed
temporary rvalue returned.
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/09/25 Raw View
Steve Clamage wrote:
> Here's what it says:
>
> "1.3.12 undefined behavior
> behavior, such as might arise upon use of an erroneous program
> construct or erroneous data, for which this International Standard
> imposes no requirements. ...
> [Note: permissible undefined behavior ranges from ignoring the situation
> completely with unpredictable results, to behaving during translation
> or program execution in a documented manner characteristic of the
> environment (with or without the issuance of a diagnostic message),
> to terminating a translation or execution (with the issuance of a
> diagnostic message). ...]"
>
> Notice that "terminating translation" is explictly mentioned as a
> possibility, but the the key phrase is "imposes NO requirements"
> (emphasis mine).
But IMO this makes no sens. Runtime undefined behaviour
is something which happens at run-time.
> If you write, for example, at namespace scope
> const int k = constant_expression_that_divides_by_zero;
> the results are undefined.
No. This is ill-formed.
--
Valentin Bonnard
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Barry Margolin <barmar@bbnplanet.com>
Date: 1999/09/25 Raw View
In article <7sdgbv$9qa$1@nnrp1.deja.com>,
<James.Kanze@dresdner-bank.com> wrote:
>In article <37E7E515.43E4@wanadoo.fr>,
> Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:
>> James Kuyper wrote:
>
>> > The standard includes a refusal to compile as one of the permitted
>> > kinds of undefined behavior.
>
>> IMO this is utter non-sens.
>
>Well, the standard quite explicitly says that this is one of the
>permitted kinds of undefined behavior.
>
>The only restriction is that the undefined behavior must actually
>exist. The expression x/0 is *not* undefined behavior -- the actual
>division will be, however, when it is executed. So the compiler can
>only refuse to compile if it can prove that the expression will be
>executed. For most compilers, this is impossible -- if I never invoke
>the generated program, the code won't be executed.
I don't think it has to go that far up the call tree to the shell. If you
never invoke the program, you wouldn't notice that the program was never
compiled, either, so it's safe for the compiler not to generate an
executable if it can determine that all paths from main() lead to undefined
behavior.
--
Barry Margolin, barmar@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/09/25 Raw View
In article <37eaae54.19392341@news.csrlink.net>,
jpotter@falcon.lhup.edu (John Potter) wrote:
>
> On 23 Sep 99 07:28:28 GMT, Ron Natalie <ron@sensor.com> wrote:
>
> : John Potter wrote:
> : > But, in C++, ++p returns the new value of p and it is an lvalue.
We
> : > know that the only lvalue that it can return is p, so p must have
the
> : > new value. There must be a sequence point in that prefix ++.
> : No, there is no sequence point there.
> This I know, for the standard tells me so.
> : The compiler is quite free to
> : evaluate:
> : *++p =3D 5
> : as
> : p[1] =3D 5;
> : p++;
> Why did you move the ++ to the right? There is a big difference.
I think he was simply indicating that the actual incrementation, or at
least the storing of the incremented value, could take place after the
assignment.
> : As long as everything observable has the right values at the
sequence
> : point (which in this case is at the end of the full expression),
then
> : the compiler is free to play games with the intermediate steps.
> Yep. ++p returns the lvalue p with the new value.
The expression ++p has a value, and has the characteristic of
lvalue-ness. I'm not sure I can say that it returns anything.
> There is no way
> to do that without doing it. The as-if rule says that it can change
> the semantics of the language as long as I can't tell. It's a nice
> tap dance, but it allows saying things like &++p =3D=3D &p which can no=
t
> be said in C.
You mean, of course, that the C++ grammar allows such things. Of
course, a compiler is free to change this into (p++, true) if it
wishes. (Always supposing built-in operators.)
> The problem in the original question was the thought
> that in changing the semantics, it was also possible to change the
> outcome.
> : While the whole discussion of lvalues isn't incorrect, it's not
really
> : material (which is why the poster said "does it matter" to the "Is
> : * a sequence point" The answer is it isn't, but a sequence point
isn't
> : necessary here to assure consistant results. Nothing is modified
twice,
> : nor is the contents of p used for any other purpose than determining
> : the result of the p++ subexperssion.
> You did it again. *p++ =3D 5 has no problems. It returns an rvalue fo=
r
> use by * and the increment can happen later with no questions.
> *++p =3D 5;
> add 1 to p
> return lvalue p
> get rvalue from lvalue
> dereference getting lvalue
> put 5 there
> It takes a much greater leap of faith to accept moving these things
> around than it does to simply delay storing the incremented value.
But the standard doesn't say anything like that. It says that:
- ++p is an expression which returns the incremented value of p.
- ++p is an expression which has the side effect of storing the
incremented value of p in p.
- ++p is an lvalue -- as an lvalue, it has the "address" of the
variable p.
The standard also clearly states that the side effects may occur at any
time between the preceding and the following sequence point.
(Logically, we may suppose as well that the side effect of storing the
incremented value actually occurs after the read of the initial value,
although I don't think that the compiler guarantees this, even in the
case of volatile variables.)
Lvalue-ness and side effects are perfectly orthogonal.
> The results of undefined behavior lead me to believe that compiler
> writers also have some problems with this violation of the semantics.
> (a =3D 5) +=3D 2; // Have only seen 7
> ++ ++ a; // Have only seen 9
What you actually see is irrelevant. In both cases, you have undefined
behavior, so anything you see is correct.
> x =3D 3;
> y =3D ++x + ++x + ++x; // I understand 16
> y =3D ++x + (++x + ++x); // I understand 18
I understand undefined behavior. The value might be 16 or 18 on some,
or even most, compilers.
> Delayed dereferencing of the returned lvalue covers it.
> I have also seen 15 for both.
Which is also fine. Once there is undefined behavior, the behavior is
undefined.
> y =3D x++ + x++ + x++; // 12
> y =3D x++ + (x++ + x++); // still 12
Again, all undefined behavior.
> There is a much larger set of reasonable results. It makes no sense
> for the standard to list all possible outcomes. It is much better to
> simply say that the outcome is undefined.
> Anyway, it doesn't matter. *++p =3D 5 must do the right thing and so
> must pp =3D &++p. I don't really care how. It might hurt if I do the
> silly things above; so, I don't do them.
--
James Kanze mailto: James.Kanze@dresdner-bank.com
Conseils en informatique orient=E9e objet/
Beratung in objekt orientierter Datenverarbeitung
Ziegelh=FCttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/25 Raw View
On 24 Sep 1999 16:42:42 GMT, Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:
>James.Kanze@dresdner-bank.com wrote:
>> Well, the standard quite explicitly says that this is one of the
>> permitted kinds of undefined behavior.
>
>So it's the standard which doesn't make sens.
Why does it not make sense to you? Does the analogy I gave that the
compiler refusing to compile code with undefined behavior is like
doing an abort() at runtime and then hoisting this abort() to compile
time make sense, or is the analogy faulty?
>> So the compiler can
>> only refuse to compile if it can prove that the expression will be
>> executed.
>
>That's better. (That makes sens.)
:).
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James Kuyper <kuyper@wizard.net>
Date: 1999/09/25 Raw View
James.Kanze@dresdner-bank.com wrote:
...
> Is it the fact I wrote x/0 that renders the program undefined, or is it
> the execution of a division by 0? In other words, is the following
> program legal, or can the compiler refuse to compile it?
I believe not.
> int
> main()
> {
> int const y = 0 ;
> if ( y )
> x /= y ;
Well, it would be nice to have a definition of 'x' in scope :-)
> return 0 ;
> }
>
> (Note that y is a constant integral expression -- in this case, no
> different from a literal 0.)
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James Kuyper <kuyper@wizard.net>
Date: 1999/09/25 Raw View
Hyman Rosen wrote:
>
> James.Kanze@dresdner-bank.com writes:
> > So the compiler can only refuse to compile if it can prove that the
> > expression will be executed. For most compilers, this is impossible
> > -- if I never invoke the generated program, the code won't be
> > executed.
>
> If you never invoke the generated program, then how do you know whether
> the compiler refused to compile it? :-)
At least one diagnostic is required, if it chooses to refuse to compile
it for this reason.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 1999/09/24 Raw View
Ed Brey wrote:
>
> as long as the
> results provide what is guaranteed by the order of operations imposed by the
> grammar, which is what the parse tree represents.
The parse tree does not provide any ordering of operations in C++, other
than indicating that some calculations are antecedents to others.
It's not really an "as-if" thing.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/09/24 Raw View
James.Kanze@dresdner-bank.com wrote:
>
> In article <37E7E515.43E4@wanadoo.fr>,
> Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:
> > James Kuyper wrote:
>
> > > The standard includes a refusal to compile as one of the permitted
> > > kinds of undefined behavior.
>
> > IMO this is utter non-sens.
>
> Well, the standard quite explicitly says that this is one of the
> permitted kinds of undefined behavior.
So it's the standard which doesn't make sens.
> The only restriction is that the undefined behavior must actually
> exist. The expression x/0 is *not* undefined behavior -- the actual
> division will be, however, when it is executed.
Great !
> So the compiler can
> only refuse to compile if it can prove that the expression will be
> executed.
That's better. (That makes sens.)
> For most compilers, this is impossible -- if I never invoke
> the generated program, the code won't be executed.
Of course.
> Not all undefined behavior involves runtime behavior, however.
Of course.
--
Valentin Bonnard
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Barry Margolin <barmar@bbnplanet.com>
Date: 1999/09/24 Raw View
In article <37eaae54.19392341@news.csrlink.net>,
John Potter <jpotter@falcon.lhup.edu> wrote:
>
>On 23 Sep 99 07:28:28 GMT, Ron Natalie <ron@sensor.com> wrote:
>: The compiler is quite free to
>: evaluate:
>: *++p = 5
>: as
>: p[1] = 5;
>: p++;
>
>Why did you move the ++ to the right? There is a big difference.
Even if the value of the expression isn't used? The only difference
between ++p and p++ (when p is a built-in type) is in its value. If the
expression is being evaluated only for its side effects, there's no
difference. He could have written that as:
p[1] = 5;
p = p + 1;
But p++ is equivalent to p=p+1, so he abbreviated it.
--
Barry Margolin, barmar@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/09/24 Raw View
In article <slrn7ultgg.vfb.sbnaran@localhost.localdomain>,
sbnaran@uiuc.edu wrote:
> On 23 Sep 99 07:26:31 GMT, Andrew Koenig <ark@research.att.com> wrote:
> >Siemel B. Naran <sbnaran@uiuc.edu> wrote:
> >>Yes, you are right about inline. However what I'm saying is that
> >>inline lets the compiler do the as-if optimization more than it
would
> >>otherwise. For example, with op++ inline, the compiler may replace
> >> while (begin!=end) *begin++=*end++;
> >>with
> >> while (begin!=end) { *begin=*end; ++begin,++end; }
> >It has to be careful if begin and end have user-defined types.
> >In that case, the assignment operator might be able to access
> >the value of begin or end, in which case your rewrite would
> >change externally visible behavior. Ditto in the case where
> >the assignment operator might throw an exception.
> I'm confused about line 1-4. Please explain more.
> And line 4-5 makes sense. The optimization is trickier than
> I first thought :). But I think that if 'begin' and 'end'
> are local variables (ie, variables of value rather than
> references), then the rewrite is reasonable. If there is an
> exception, then we are going to destroy 'begin' and 'end',
> and their value does not matter anyway.
Maybe.
Technically, a user defined operator++ doesn't even have to return the
same type as it is called on, so your proposed rewrite might not even be
legal -- the original type might not have an operator*.
More generally, even if it is legal, both the operator++ and the
operator* (as well as the operator=) may modify global state. If all of
the operators are user defined functions, it is guaranteed that this
global state has the new value before operator= is called. And of
course, if operator= takes references (which it almost always does), and
operator* and operator++ return references to themselves (I think some
of the STL operators do), then operator= can access their state even
without global variables.
--
James Kanze mailto: James.Kanze@dresdner-bank.com
Conseils en informatique orient e objet/
Beratung in objekt orientierter Datenverarbeitung
Ziegelh ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
Sent via Deja.com http://www.deja.com/
Before you buy.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/09/24 Raw View
In article <7sbccm$4aa$1@engnews1.eng.sun.com>,
clamage@eng.sun.com (Steve Clamage) wrote:
> sbnaran@uiuc.edu (Siemel B. Naran) writes:
> If you write, for example, at namespace scope
> const int k = constant_expression_that_divides_by_zero;
> the results are undefined. The compiler is not obligated to produce
> a runnable program. If it did, the program would have no defined
> semantics. Defined by the standard, that is.
Is it the fact I wrote x/0 that renders the program undefined, or is it
the execution of a division by 0? In other words, is the following
program legal, or can the compiler refuse to compile it?
int
main()
{
int const y = 0 ;
if ( y )
x /= y ;
return 0 ;
}
(Note that y is a constant integral expression -- in this case, no
different from a literal 0.)
Note too that I'm not trying to say in general that the compiler can
refuse to compile a program. There are a number of cases where the
undefined behavior *is* a result of how the program is written, and not
what happens at execution. I'm just talking about this one particular
case.
--
James Kanze mailto: James.Kanze@dresdner-bank.com
Conseils en informatique orient e objet/
Beratung in objekt orientierter Datenverarbeitung
Ziegelh ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
Sent via Deja.com http://www.deja.com/
Before you buy.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/09/24 Raw View
James.Kanze@dresdner-bank.com writes:
> So the compiler can only refuse to compile if it can prove that the
> expression will be executed. For most compilers, this is impossible
> -- if I never invoke the generated program, the code won't be
> executed.
If you never invoke the generated program, then how do you know whether
the compiler refused to compile it? :-)
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/09/24 Raw View
In article <7sbccm$4aa$1@engnews1.eng.sun.com>, Steve Clamage
<clamage@eng.sun.com> writes
>I would prefer the compiler to treat this code as an error, since
>I would not knowingly write such code. If my code has such errors,
>I would ordinarily prefer that no exectuable be produced. That
>would ensure that I don't waste time testing the program, or worse,
>deliver it to a customer.
>
>I would not want the standard to require that the C++ implementation
>produce some sort of runnable program no matter what undefined
>behavior the program contains. As it is, the C++ implementation
>can behave in any way that its provider and customers deem suitable.
My memory is that this is subtly different from the C requirement,
where, IIRC, a compiler may only abort compilation if it can prove that
the code in question will be executed if compiled. I.e. there is
nothing wrong with divide by zero if it is never executed.
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/09/24 Raw View
In article <7savq1$qbg2@interserv.etn.com>, Ed Brey
<brey@afd.mke.etn.com> writes
>Does the fact that there are member function calls of cout make a
>difference? Clearly operator<<(++i) must be evaluated before
>operator<<(--i), because operator<<(--i) needs the results of
>operator<<(++i) for its this pointer. The question is does this ordering
>force the --i to have to be evaluated before the ++i?
No. But it does require the side-effect of each evaluation to be
complete before the relevant function call.
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 1999/09/24 Raw View
Ed Brey wrote:
>
> Clearly operator<<(++i) must be evaluated before...
but that doesn't say when the values of ++i and --i
need be computed. Those subexpressions could be computed
before any of the operator<< functions are called.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/09/24 Raw View
In article <7savdf$onl4@interserv.etn.com>,
"Ed Brey" <brey@afd.mke.etn.com> wrote:
>
> Siemel B. Naran <sbnaran@uiuc.edu> wrote in message
> news:slrn7uflrh.1g5.sbnaran@localhost.localdomain...
> > On 21 Sep 99 18:34:32 GMT, James.Kanze@dresdner-bank.com
> > >From the rule that the compiler may rearrange builtin operators, I
> > deduced that "*++i=c" is equivalent to either of
> > *i=c; ++i;
> > ++i; *i=c;
> The compiler can't just willy-nilly rearrange builtin operators.
Rather, it
> can only work on subtrees in any order. However, it must complete
> evaluation of a subtree before using the result of its evaluation,
which is
> why "*++i=c" is necessary equivlent to "++i; *i=c".
Could you please indicate where in the standard it says that. I know
that there was a request for interpretation of the C standard, to which
the response said that functions couldn't be interleaved, basically
because the function call was a sequence point. But as far as I know,
the only requirements imposing ordering involve sequence points, and the
common sense aspect that you cannot use a result before evaluating it.
The expression *++i = c is legal and defined, not because of any
ordering requirements, but because it never modifies the same value
twice.
> The parse tree is:
>
> =
> / \
> * c
> |
> ++
> |
> i
> The compiler can evaluation either "c" or "*++i" first, but "++i" must
be
> evaluated before the evaluation of "*" begins.
There are two aspects involved here:
- The compiler must somehow obtain the results of ++i before
dereferencing it. I don't think that the standard actually says
this, but basic causality does -- the * operator operates on an
operand, and cannot do so before the operand exists.
- The expression ++i has a side effect of modifying i. This side
effect must take place before the next sequence point -- in this
case the end of the expression. It may take place after the
assignment, or before. The standard makes no requirements
concerning this.
Of course, if the variables involved are not volatile, the two
modifications (the ++ operator and the assignment) are not observable
behavior, so the compiler has a lot more leeway.
--
James Kanze mailto: James.Kanze@dresdner-bank.com
Conseils en informatique orient e objet/
Beratung in objekt orientierter Datenverarbeitung
Ziegelh ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Ed Brey" <brey@afd.mke.etn.com>
Date: 1999/09/24 Raw View
Ron Natalie <ron@sensor.com> wrote in message
news:37E937D7.846978CE@sensor.com...
> Ed Brey wrote:
> >
> > why "*++i=c" is necessary equivlent to "++i; *i=c".
> > [...]
> > The compiler can evaluation either "c" or "*++i" first, but "++i" must
be
> > evaluated before the evaluation of "*" begins.
> >
> Sorry, this is INCORRECT. The compiler is not so constrained. It can
> rearranage the operations all it want until it hits a sequence point.
> Notably, it is quite legal and possible for the compiler to do:
>
> i[1] = c;
> i++;'
>
> The side effects of the evaluation of ++i can happen at any time
> up until the evaluation of the sequence point.
Thank you. I was giving the explanation from an as-if standpoint, trying to
explain why "*++i=c" cannot be the same as "*i=c; ++c". The compiler can do
whatever magic it wants (indeed, your arrangement prevents a
read-after-write hazard and its potential pipeline stall), as long as the
results provide what is guaranteed by the order of operations imposed by the
grammar, which is what the parse tree represents.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/09/24 Raw View
In article <37e810ad.18856802@news.csrlink.net>,
jpotter@falcon.lhup.edu (John Potter) wrote:
>
> On 20 Sep 99 23:46:31 GMT, sbnaran@uiuc.edu (Siemel B. Naran) wrote:
>
> : On 20 Sep 1999 16:30:45 GMT, Andrew Koenig <ark@research.att.com>
wrote:
> : >Siemel B. Naran <sbnaran@uiuc.edu> wrote:
> : >>I think that "*++i=3Dc" may be equivalent to either of
> : >> ++i , *i=3Dc ; // someone posted an example with this as the
meaning
> : >> *i=3Dc , ++i ; // principle behind this: do operations at end of
statement
> : >No -- *++i=3Dc is equivalent to the first example above only.
> : >(assuming that i is a pointer, which is the only built-in type
> : >that would cause the example to type-check)
> : >++i is defined as (i=3Di+1), so *++i=3Dc means *(i=3Di+1)=3Dc
> : >There is no problem with sequence points, because i is modified
> : >only once, and there is no question that what is being
> : >derefenced is (i=3Di+1), which is i after it was incremented.
What is being dereferenced is the results of the expression ++i (which
has a value equal to i+1). *NOT* i itself. So the actual modification
can take place at any time up til the next sequence point.
> : So '*' is a sequence point?
> Well, no. Let's see if we can make non^H^H^Hsense of this.
> In C, ++p returns the new value of p and it is an rvalue.
> int i[2];
> int* p =3D i;
> *++p =3D 5;
> Sure enough, i[1] is 5 but the code is:
> int* reg =3D p + 1;
> *reg =3D 5;
> p =3D reg;
> That's ok because the rvalue which was dereferenced was p + 1.
> But, in C++, ++p returns the new value of p and it is an lvalue. We
> know that the only lvalue that it can return is p, so p must have the
> new value.
No. Any attempt to access p (read or write) other than to determine the
value to be written to p (which is the result of ++p) is undefined
behavior. The only thing guaranteed is that the modification of p will
take place before the next sequence point.
> There must be a sequence point in that prefix ++.
There isn't.
> Let's
> prove it with an absurdity which also covers assignment and its
> lvalue.
> int i[2];
> int* p(i);
> int** pp;
> int*** ppp;
> ***(ppp =3D &(pp =3D &++p)) =3D 5;
> Sure enough, all of the variables have the expected values, but the
> code is:
> int* reg =3D p + 1;
> *reg =3D 5;
> ppp =3D &pp;
> pp =3D &p
> p =3D reg;
The original expression contains undefined behavior, see 5/4: "Between
the previous and next sequence point a scalar 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." The above expression modifies both pp and ppp, and
accesses them as well other than to determine the value to be written in
the access.
> Totally ignored all of the semantics explained in the standard. Let's
> try to catch them.
> int i[3];
> int* p(i);
> ++ ++ p;
> I didn't get the expected results, in fact I didn't get any output.
The
> code was:
> <self mail comp-std-c++@moderators.isc.org
> -s 'Look at the dumb thing I did'
> Fortunately, it seems to have been lost along with my prior ramblings
> on this subject ;-)
> That damned undefined behavior, I can't determine if ++p really
> returns an lvalue any other way. As-if rules!
Sure you can.
int i[2] ;
int* p( i ) ;
int*& pr =3D ++ p ;
Only works if ++ p is an lvalue.
> So ++p returns the new value of p and *++p will work regardless of
> when the new value actually gets placed in p. C++ is a bit trickier
> than C because we get these lvalues which may not be lvalues that
> get converted to rvalues. In the absence of a sequence point, it
> can do whatever it wants as long as we can't tell.
Correct. Even with sequence points, it can do whatever it wants as long
as we can't tell. Declaring the variables volatile, however, permits
observing their actual modification; i.e. we can tell.
> The bottom line is that the lvalues from prefix ++/-- and =3D are a
> crock of brown stuff other than allowing taking the address. Any
> other use is undefined behavior.
Any use of an lvalue presupposes in some way taking its address. Not in
the C++ sense (operator &), but in the physical sense. In the C++
sense, probably the most frequent use of this sort of lvalue-ness is not
taking the address, but binding the object to a reference. Binding an
lvalue to a reference means that the reference refers to that specific
object.
> An interesting side effect is
> that the STL requires an operator=3D which returns a reference although
> there is no way that it can be used (T might be builtin).
I would almost be surprised if there weren't instances in the STL of
things like " return a =3D b ", where the return type is a reference.
--
James Kanze mailto: James.Kanze@dresdner-bank.com
Conseils en informatique orient=E9e objet/
Beratung in objekt orientierter Datenverarbeitung
Ziegelh=FCttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/09/24 Raw View
In article <7sdo00$qbg4@interserv.etn.com>, Ed Brey
<brey@afd.mke.etn.com> writes
>The postfix autoincrement operator is unique in this case in that it
>provides access to the prior value of its operand. What in the IS keeps the
>requirement in question from rendering the example's behavior undefined?
At worst 'a close and careful reading' (translation, 'we may not have
said it but we meant to').
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/09/24 Raw View
"Ed Brey" <brey@afd.mke.etn.com> writes:
> cout.operator<<(++i).operator<<(endl).operator<<(--i).operator<<(endl);
> Does the fact that there are member function calls of cout make a
> difference? Clearly operator<<(++i) must be evaluated before
> operator<<(--i), because operator<<(--i) needs the results of
> operator<<(++i) for its this pointer. The question is does this ordering
> force the --i to have to be evaluated before the ++i?
No. It's still undefined. There's a sequence point before each call,
but one legal order of evaluation is to evaluate all of the arguments
before any call is made. This menas that we can evaluate --i and ++i
between two sequence points, so the behavior is undefined.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/24 Raw View
On 23 Sep 99 07:26:31 GMT, Andrew Koenig <ark@research.att.com> wrote:
>Siemel B. Naran <sbnaran@uiuc.edu> wrote:
>>Yes, you are right about inline. However what I'm saying is that
>>inline lets the compiler do the as-if optimization more than it would
>>otherwise. For example, with op++ inline, the compiler may replace
>> while (begin!=end) *begin++=*end++;
>>with
>> while (begin!=end) { *begin=*end; ++begin,++end; }
>
>It has to be careful if begin and end have user-defined types.
>In that case, the assignment operator might be able to access
>the value of begin or end, in which case your rewrite would
>change externally visible behavior. Ditto in the case where
>the assignment operator might throw an exception.
I'm confused about line 1-4. Please explain more.
And line 4-5 makes sense. The optimization is trickier than
I first thought :). But I think that if 'begin' and 'end'
are local variables (ie, variables of value rather than
references), then the rewrite is reasonable. If there is an
exception, then we are going to destroy 'begin' and 'end',
and their value does not matter anyway.
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/09/24 Raw View
In article <37E7E515.43E4@wanadoo.fr>,
Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:
> James Kuyper wrote:
> > The standard includes a refusal to compile as one of the permitted
> > kinds of undefined behavior.
> IMO this is utter non-sens.
Well, the standard quite explicitly says that this is one of the
permitted kinds of undefined behavior.
The only restriction is that the undefined behavior must actually
exist. The expression x/0 is *not* undefined behavior -- the actual
division will be, however, when it is executed. So the compiler can
only refuse to compile if it can prove that the expression will be
executed. For most compilers, this is impossible -- if I never invoke
the generated program, the code won't be executed.
Not all undefined behavior involves runtime behavior, however.
Undefined behavior may occur at many different phases of compilation as
well. For example, I for one would be very pleased if the compiler gave
me an error message and refused to compile if the ODR was violated; the
standard most definitly allows this.
--
James Kanze mailto: James.Kanze@dresdner-bank.com
Conseils en informatique orient e objet/
Beratung in objekt orientierter Datenverarbeitung
Ziegelh ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: comeau@panix.com (Greg Comeau)
Date: 1999/09/24 Raw View
In article <7savq1$qbg2@interserv.etn.com> "Ed Brey" <brey@afd.mke.etn.com> writes:
>cout.operator<<(++i).operator<<(endl).operator<<(--i).operator<<(endl);
>....
>Clearly operator<<(++i) must be evaluated before
>operator<<(--i), because operator<<(--i) needs the results of
>operator<<(++i) for its this pointer.
Yes, but...
>The question is does this ordering
>force the --i to have to be evaluated before the ++i?
.... I don't see why. The sequence points here do not impact that the
++i and --i are arguments to functions and distinct from the calls and
. operators
- Greg
--
Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418-3214
Producers of Comeau C/C++ 4.2.38 -- NOTE 4.2.42 BETAS NOW AVAILABLE
Email: comeau@comeaucomputing.com / Voice:718-945-0009 / Fax:718-441-2310
*** WEB: http://www.comeaucomputing.com ***
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/09/23 Raw View
In article <37e813d5.19665084@news.csrlink.net>,
jpotter@falcon.lhup.edu (John Potter) wrote:
>
> On 21 Sep 1999 15:43:13 GMT, ark@research.att.com (Andrew Koenig)
wrote:
>
> : In article <slrn7ucvcn.nn3.sbnaran@localhost.localdomain>,
> : Siemel B. Naran <sbnaran@uiuc.edu> wrote:
>
> : > So '*' is a sequence point?
No.
> : Does it matter?
>
> Maybe.
>
> struct S { S** p; };
> S s[3];
> S* q(s);
> s[1].p = &q;
> ++*(++q)->p;
> Modifies q twice with a (*) sequence point between.
And is undefined behavior.
--
James Kanze mailto: James.Kanze@dresdner-bank.com
Conseils en informatique orient e objet/
Beratung in objekt orientierter Datenverarbeitung
Ziegelh ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/09/23 Raw View
In article <slrn7ugo4v.1g5.sbnaran@localhost.localdomain>,
sbnaran@uiuc.edu wrote:
> On 21 Sep 1999 16:25:10 GMT, James.Kanze@dresdner-bank.com
> >In article <slrn7uaaln.pla.sbnaran@localhost.localdomain>,
>
> >I'm tempted to say that if it takes getting used to, it is obscure:-).
>
> :)
>
> >> That's why I find
> >> *++i = c;
> >> just as pleasing. Some of my old code still uses this style.
> >The use of preincrement is a much less wide-spread conventional idiom,
> >and I have some difficulty finding a general equivalent (in a range of
> >languages).
> Find space in the container for which 'i' is an iterator to hold one
> more element, then set this new element equal to 'c'.
Well, I'd argue that "reading/writing from a file" is a far more
widespread concept in programming languages than "finding space in a
container for which i is an iterator ...".
--
James Kanze mailto: James.Kanze@dresdner-bank.com
Conseils en informatique orient e objet/
Beratung in objekt orientierter Datenverarbeitung
Ziegelh ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Ed Brey" <brey@afd.mke.etn.com>
Date: 1999/09/23 Raw View
Ron Natalie <ron@sensor.com> wrote in message
news:37E9388A.A4E769BB@sensor.com...
>
> It goes on to say: the prior value shall be accessed only to determine
> the value to be stored.
This requirement seems overly restrictive. For example, consider:
if (i++);
Here the prior value of b is accessed for two purposes: to determine the
value to be stored into i, and to determine whether the if's expression is
true (via implicit cast to bool). Therefore, the expression seems to
violate the requirement, since the prior value is accessed in a way other
than what is allowed.
The postfix autoincrement operator is unique in this case in that it
provides access to the prior value of its operand. What in the IS keeps the
requirement in question from rendering the example's behavior undefined?
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/09/24 Raw View
Hyman Rosen <hymie@prolifics.com> writes:
> Jeff Rife <wevsr@nabs.net> writes:
> > I completely understand why modifying a object more than once between
> > sequence points is undefined. But, as far as I can tell from the Standard,
> > this also invokes undefined behavior:
> > i = 5;
> > cerr << i << endl << --i << endl;
> > Is it undefined, and, if not, why not?
>
> No, this is not undefined, merely unspecified.
Oops, I'm wrong, as several people have pointed out.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/09/24 Raw View
On 23 Sep 99 07:28:28 GMT, Ron Natalie <ron@sensor.com> wrote:
: John Potter wrote:
: >
: >
: > But, in C++, ++p returns the new value of p and it is an lvalue. We
: > know that the only lvalue that it can return is p, so p must have the
: > new value. There must be a sequence point in that prefix ++.
:
: No, there is no sequence point there.
This I know, for the standard tells me so.
: The compiler is quite free to
: evaluate:
: *++p = 5
: as
: p[1] = 5;
: p++;
Why did you move the ++ to the right? There is a big difference.
: As long as everything observable has the right values at the sequence
: point (which in this case is at the end of the full expression), then
: the compiler is free to play games with the intermediate steps.
Yep. ++p returns the lvalue p with the new value. There is no way
to do that without doing it. The as-if rule says that it can change
the semantics of the language as long as I can't tell. It's a nice
tap dance, but it allows saying things like &++p == &p which can not
be said in C. The problem in the original question was the thought
that in changing the semantics, it was also possible to change the
outcome.
: While the whole discussion of lvalues isn't incorrect, it's not really
: material (which is why the poster said "does it matter" to the "Is
: * a sequence point" The answer is it isn't, but a sequence point isn't
: necessary here to assure consistant results. Nothing is modified twice,
: nor is the contents of p used for any other purpose than determining
: the result of the p++ subexperssion.
You did it again. *p++ = 5 has no problems. It returns an rvalue for
use by * and the increment can happen later with no questions.
*++p = 5;
add 1 to p
return lvalue p
get rvalue from lvalue
dereference getting lvalue
put 5 there
It takes a much greater leap of faith to accept moving these things
around than it does to simply delay storing the incremented value.
The results of undefined behavior lead me to believe that compiler
writers also have some problems with this violation of the semantics.
(a = 5) += 2; // Have only seen 7
++ ++ a; // Have only seen 9
x = 3;
y = ++x + ++x + ++x; // I understand 16
y = ++x + (++x + ++x); // I understand 18
Delayed dereferencing of the returned lvalue covers it.
I have also seen 15 for both.
y = x++ + x++ + x++; // 12
y = x++ + (x++ + x++); // still 12
There is a much larger set of reasonable results. It makes no sense
for the standard to list all possible outcomes. It is much better to
simply say that the outcome is undefined.
Anyway, it doesn't matter. *++p = 5 must do the right thing and so
must pp = &++p. I don't really care how. It might hurt if I do the
silly things above; so, I don't do them.
John
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/09/23 Raw View
In article <slrn7uflrh.1g5.sbnaran@localhost.localdomain>, Siemel B.
Naran <sbnaran@uiuc.edu> writes
>>From the rule that the compiler may rearrange builtin operators, I
>deduced that "*++i=c" is equivalent to either of
> *i=c; ++i;
> ++i; *i=c;
>
>Later I thought that it could be equivalent to
> ++i; i=c; *i;
> *i; i=c; ++i;
> etc.
>
>Evidently, I have no clue about this business of sequence points.
Sequence points are about side-effects and those include the process of
writing data back to storage.
*++i = c;
I believe reads as :
1) at some convenient moment evaluate c (there do not appear to be side-
effects here)
2) fetch i and increment it, keep that result and at some time before
the next sequence point write it back to i.
3) dereference the result you have from 2 and use it as an lvalue. Not
a very good description I am afraid, but hopefully enough.
4) convert the value for c into the type of *++i and mark it as to be
written back to the lvalue from 3.
5) complete all the write processes in any order (including in parallel)
that you like
6) return a reference to *++i
Note that internal sequence points brought about by function calls do
not protect their arguments from side-effect problems because all the
arguments for function calls in a whole expression can be evaluated
first, and the side-effects delayed, mixed up, run in parallel etc. All
that the function sequence points require is that the side-effects of
evaluating arguments must be complete before the function is called.
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/09/23 Raw View
In article <MPG.125232eb9b8e1d1f989704@news.nabs.net>, Jeff Rife
<wevsr@nabs.net> writes
>I completely understand why modifying a object more than once between
>sequence points is undefined. But, as far as I can tell from the Standard,
>this also invokes undefined behavior:
>
>i = 5;
>cerr << i << endl << --i << endl;
>
>Is it undefined, and, if not, why not?
It is (undefined) because the full rule requires that any access to the
value of an object that is to be written to between sequence points
shall be for the purpose of determining the value to be written. The
first use of i in the above breeches this constraint.
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/09/23 Raw View
James.Kanze@dresdner-bank.com wrote:
[...]
> > That's why I find
> > *++i = c;
> > just as pleasing. Some of my old code still uses this style.
>
> The use of preincrement is a much less wide-spread conventional idiom,
> and I have some difficulty finding a general equivalent (in a range of
> languages).
You could implement a stack in C as
int stack_mem[1000];
static int* sp = stack_mem; // stack pointer
void push(int i)
{
*++sp=i;
}
int top()
{
return *sp;
}
int pop()
{
return *sp--;
}
So push can be used for pre-increment equivalents (where
the stack grows in the appropriate direction).
Of course, you can also build your stack with post-increment
push and pre-increment pop (the version above wastes one int
for the benefit of the top() operation). In any case, if one
operation of the stack uses post-increment, the other one
needs pre-increment.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: comeau@panix.com (Greg Comeau)
Date: 1999/09/23 Raw View
In article <slrn7ufm0a.1g5.sbnaran@localhost.localdomain> sbnaran@uiuc.edu writes:
>inline lets the compiler do the as-if optimization more than it would
>otherwise. For example, with op++ inline, the compiler may replace
> while (begin!=end) *begin++=*end++;
>with
> while (begin!=end) { *begin=*end; ++begin,++end; }
Really? Upon what facts or even premise do you base this?
Also, I don't see the difference you are trying to bring forth
between the two forms you show. That is, you seem to be showing
i++ vs i=i+1 but I don't know why.
- Greg
--
Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418-3214
Producers of Comeau C/C++ 4.2.38 -- NOTE 4.2.42 BETAS NOW AVAILABLE
Email: comeau@comeaucomputing.com / Voice:718-945-0009 / Fax:718-441-2310
*** WEB: http://www.comeaucomputing.com ***
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: comeau@panix.com (Greg Comeau)
Date: 1999/09/23 Raw View
In article <MPG.125232eb9b8e1d1f989704@news.nabs.net> Jeff Rife <wevsr@nabs.net> writes:
>Siemel B. Naran (sbnaran@uiuc.edu) wrote:
>
>> > i = 5;
>> > cerr << ++i << endl << --i << endl;
>>
>> This is undefined.
>> The compiler may evaluate the 5 operands of the second statement
>> cerr
>> ++i
>> endl
>> --i
>> endl
>> in any order, and possibly even at the same time. In particular,
>> the compiler may evaluate "++i" before "--i", or "--i" before "++i".
>
>I completely understand why modifying a object more than once between
>sequence points is undefined. But, as far as I can tell from the Standard,
>this also invokes undefined behavior:
>
>i = 5;
>cerr << i << endl << --i << endl;
>
>Is it undefined, and, if not, why not?
It is unspecified when side-effects will get done, that is,
the order of evaluation can have it that --i gets done before i,
even though i is only modified once. This is just the classic
a[i] = i++; case.
- Greg
--
Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418-3214
Producers of Comeau C/C++ 4.2.38 -- NOTE 4.2.42 BETAS NOW AVAILABLE
Email: comeau@comeaucomputing.com / Voice:718-945-0009 / Fax:718-441-2310
*** WEB: http://www.comeaucomputing.com ***
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Ed Brey" <brey@afd.mke.etn.com>
Date: 1999/09/23 Raw View
Siemel B. Naran <sbnaran@uiuc.edu> wrote in message
news:slrn7ueat1.ukm.sbnaran@localhost.localdomain...
> On 20 Sep 99 23:47:45 GMT, David R Tribble <david@tribble.com> wrote:
>
> It makes sense with a parse tree.
>
> cout << ++i << endl << --i << endl;
>
> [parse tree (and other stuff) snipped]
Is a parse tree appropriate for an expression like this? The reason I raise
the question is because operator<< in this case is member function, i.e.
ostream& ostream::operator<<(int);
rather than
ostream& operator<<(ostream&, int);
This means that the statement in question is equivalent to:
cout.operator<<(++i).operator<<(endl).operator<<(--i).operator<<(endl);
Does the fact that there are member function calls of cout make a
difference? Clearly operator<<(++i) must be evaluated before
operator<<(--i), because operator<<(--i) needs the results of
operator<<(++i) for its this pointer. The question is does this ordering
force the --i to have to be evaluated before the ++i?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 1999/09/23 Raw View
John Potter wrote:
>
>
> But, in C++, ++p returns the new value of p and it is an lvalue. We
> know that the only lvalue that it can return is p, so p must have the
> new value. There must be a sequence point in that prefix ++.
No, there is no sequence point there. The compiler is quite free to
evaluate:
*++p = 5
as
p[1] = 5;
p++;
As long as everything observable has the right values at the sequence
point (which in this case is at the end of the full expression), then
the compiler is free to play games with the intermediate steps.
While the whole discussion of lvalues isn't incorrect, it's not really
material (which is why the poster said "does it matter" to the "Is
* a sequence point" The answer is it isn't, but a sequence point isn't
necessary here to assure consistant results. Nothing is modified twice,
nor is the contents of p used for any other purpose than determining
the result of the p++ subexperssion.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/09/23 Raw View
sbnaran@uiuc.edu (Siemel B. Naran) writes:
>On 22 Sep 99 08:38:45 GMT, Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:
>>James Kuyper wrote:
>>> The standard includes a refusal to compile as one of the permitted
>>> kinds of undefined behavior.
>>
>>IMO this is utter non-sens.
>I think James Kuyper is right. Refusing to compile the code is like
>putting an assert(false) in the runtime code, and then hoisting this
>runtime code into the compile time -- kind of like doing the
>assert(false) at compile time.
I'm confused about the terms of discourse here. Are we talking
about what the standard says, or what it should say?
Here's what it says:
"1.3.12 undefined behavior
behavior, such as might arise upon use of an erroneous program
construct or erroneous data, for which this International Standard
imposes no requirements. ...
[Note: permissible undefined behavior ranges from ignoring the situation
completely with unpredictable results, to behaving during translation
or program execution in a documented manner characteristic of the
environment (with or without the issuance of a diagnostic message),
to terminating a translation or execution (with the issuance of a
diagnostic message). ...]"
Notice that "terminating translation" is explictly mentioned as a
possibility, but the the key phrase is "imposes NO requirements"
(emphasis mine).
If you write, for example, at namespace scope
const int k = constant_expression_that_divides_by_zero;
the results are undefined. The compiler is not obligated to produce
a runnable program. If it did, the program would have no defined
semantics. Defined by the standard, that is.
Of course, the implementation could choose to define the results and
proceed accordingly. Or not define the results and press on
regardless, yielding, ummmm, something.
So what should the standard say?
I would prefer the compiler to treat this code as an error, since
I would not knowingly write such code. If my code has such errors,
I would ordinarily prefer that no exectuable be produced. That
would ensure that I don't waste time testing the program, or worse,
deliver it to a customer.
I would not want the standard to require that the C++ implementation
produce some sort of runnable program no matter what undefined
behavior the program contains. As it is, the C++ implementation
can behave in any way that its provider and customers deem suitable.
--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 1999/09/23 Raw View
Ed Brey wrote:
>
>
> why "*++i=c" is necessary equivlent to "++i; *i=c".
>
> The parse tree is:
>
> =
> / \
> * c
> |
> ++
> |
> i
>
> The compiler can evaluation either "c" or "*++i" first, but "++i" must be
> evaluated before the evaluation of "*" begins.
>
Sorry, this is INCORRECT. The compiler is not so constrained. It can
rearranage the operations all it want until it hits a sequence point.
Notably, it is quite legal and possible for the compiler to do:
i[1] = c;
i++;'
The side effects of the evaluation of ++i can happen at any time
up until the evaluation of the sequence point.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/09/23 Raw View
On 22 Sep 1999 16:59:06 GMT, Hyman Rosen <hymie@prolifics.com> wrote:
: Jeff Rife <wevsr@nabs.net> writes:
: > I completely understand why modifying a object more than once between
: > sequence points is undefined. But, as far as I can tell from the Standard,
: > this also invokes undefined behavior:
: > i = 5;
: > cerr << i << endl << --i << endl;
: > Is it undefined, and, if not, why not?
:
: No, this is not undefined, merely unspecified. 5/4 explains that the
: order of evaluation of subexpressions and side-effects is unspecified,
: and for every possible order, no object should be modified more than
: once between sequence points. It's the multiple modification which
: causes undefined behavior, while your case is merely unspecified.
No, it is undefined. Take another look at 5/4. If the left i is
accessed prior to the --i, it is a use of the old value for a
purpose other than determining the new value. This is one of the
valid sequences; therefor, the requirements are not met and the
behavior is undefined.
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/09/22 Raw View
Jeff Rife <wevsr@nabs.net> writes:
> I completely understand why modifying a object more than once between
> sequence points is undefined. But, as far as I can tell from the Standard,
> this also invokes undefined behavior:
> i = 5;
> cerr << i << endl << --i << endl;
> Is it undefined, and, if not, why not?
No, this is not undefined, merely unspecified. 5/4 explains that the
order of evaluation of subexpressions and side-effects is unspecified,
and for every possible order, no object should be modified more than
once between sequence points. It's the multiple modification which
causes undefined behavior, while your case is merely unspecified.
Your code must output '5\n4\n' or '4\n4\n', but the Standard does not
specify which, nor does it even require that the output should be the
same each time this statement is encountered.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Ed Brey" <brey@afd.mke.etn.com>
Date: 1999/09/22 Raw View
Siemel B. Naran <sbnaran@uiuc.edu> wrote in message
news:slrn7uflrh.1g5.sbnaran@localhost.localdomain...
> On 21 Sep 99 18:34:32 GMT, James.Kanze@dresdner-bank.com
>
> >From the rule that the compiler may rearrange builtin operators, I
> deduced that "*++i=c" is equivalent to either of
> *i=c; ++i;
> ++i; *i=c;
The compiler can't just willy-nilly rearrange builtin operators. Rather, it
can only work on subtrees in any order. However, it must complete
evaluation of a subtree before using the result of its evaluation, which is
why "*++i=c" is necessary equivlent to "++i; *i=c".
The parse tree is:
=
/ \
* c
|
++
|
i
The compiler can evaluation either "c" or "*++i" first, but "++i" must be
evaluated before the evaluation of "*" begins.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/22 Raw View
On 22 Sep 99 08:38:45 GMT, Valentin Bonnard <Bonnard.V@wanadoo.fr> wrote:
>James Kuyper wrote:
>> The standard includes a refusal to compile as one of the permitted
>> kinds of undefined behavior.
>
>IMO this is utter non-sens.
I think James Kuyper is right. Refusing to compile the code is like
putting an assert(false) in the runtime code, and then hoisting this
runtime code into the compile time -- kind of like doing the
assert(false) at compile time.
--
--------------
siemel b naran
--------------
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/09/22 Raw View
In article <t7yadz2azi.fsf@calumny.jyacc.com>, Hyman Rosen
<hymie@prolifics.com> writes
>No, this is not undefined, merely unspecified. 5/4 explains that the
>order of evaluation of subexpressions and side-effects is unspecified,
>and for every possible order, no object should be modified more than
>once between sequence points. It's the multiple modification which
>causes undefined behavior, while your case is merely unspecified.
I think you are mistaken. The write to i is probably not an atomic
operation and a stupid compiler could try to evaluate the first use of i
whilst the new value from the second was still being written. Of course
this is unlikely to happen in such an obvious way, but throw in a couple
of aliases with a good optimiser and you are in trouble.
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 1999/09/22 Raw View
Hyman Rosen wrote:
>
> No, this is not undefined, merely unspecified. 5/4 explains that the
> order of evaluation of subexpressions and side-effects is unspecified,
> and for every possible order, no object should be modified more than
> once between sequence points. It's the multiple modification which
> causes undefined behavior, while your case is merely unspecified.
It goes on to say: the prior value shall be accessed only to determine
the value to be stored.
It's undefined behavior because i is read for purposes other than to
store it's new value.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: ark@research.att.com (Andrew Koenig)
Date: 1999/09/23 Raw View
In article <37e813d5.19665084@news.csrlink.net>,
John Potter <jpotter@falcon.lhup.edu> wrote:
>struct S { S** p; };
>S s[3];
>S* q(s);
>s[1].p = &q;
>++*(++q)->p;
>Modifies q twice with a (*) sequence point between.
>But, does it matter?
I was asking the question in the context of the original
example.
--
Andrew Koenig, ark@research.att.com, http://www.research.att.com/info/ark
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James Kuyper <kuyper@wizard.net>
Date: 1999/09/20 Raw View
Roman Belenov wrote:
>
> Hello Steve,
>
> SC> But that expectation is not justified. "Undefined behavior" means
> SC> the standard places NO requirements on the implementation. Any
> SC> result, including "-1", "42", a refusal to compile, or a run-time
> ^^^^^^^^^^^^^^^^^^^^
> SC> abort, is allowed.
>
> IMHO this particular behaviour is not standard - the code must be
> compiled, even though the resulting binary may destroy the Earth.
The standard includes a refusal to compile as one of the permitted
kinds of undefined behavior. This is true of any undefined behavior, not
just this particular case.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Barry Margolin <barmar@bbnplanet.com>
Date: 1999/09/20 Raw View
In article <slrn7u6cn4.a4f.sbnaran@localhost.localdomain>,
Siemel B. Naran <sbnaran@uiuc.edu> wrote:
>
>On 17 Sep 1999 19:28:00 GMT, Barry Margolin <barmar@bbnplanet.com> wrote:
>>Siemel B. Naran <sbnaran@uiuc.edu> wrote:
>
>>>It is mysterious/bizarre that the result of builtin operators and
>>>user defined operators are different.
>>
>>There are generally more opportunities for optimization of built-in
>>operators, because they frequently correspond closely with machine
>>instructions. C programmers expect them to generate very efficient code
>>that takes advantage of this correlation. But when using user-defined
>>operators, they expect their functions to be called; they're just using the
>>operator overload syntax as a shorthand.
>
>The as-if rule allows optimizers to do whatever optimizations they please
>as long as these optimizations do not change the observable behavior.
>From this point of view, a user defined class Int should be just as
>efficient as a builtin type class int. I think that compiler KCC does
>do this degree of optimization (so my words are not just all talk and
>no action). And if this is the case, I prefer the same set of rules
>for user operators and builtin operators.
Because of separate compilation, it's often not possible for a compiler to
do as much optimization of user-defined operators. There may be some cases
where the compiler can get close, but they're not common.
So the issue isn't whether you can optimize user-defined operators as well
as built-ins, but whether you're willing to accept built-in operators that
are slowed down so that they'll implement the same semantics as
user-defined operators.
That said, I suppose there's a middle ground. The optimizations that are
enabled by this rule are generally pretty tiny, and it would be a rare
program that would actually perform noticeably differently as a result of
them. The language could specify particular semantics, but implementors
could provide implementation-dependent compiler options (perhaps a pragma
that just covers a particular section of the program) to enable
optimization that would violate these semantics. This option should only
be needed in rare instances, when the programmer needs the performance
improvement more than standard-conforming semantics.
--
Barry Margolin, barmar@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/20 Raw View
On 20 Sep 1999 16:30:45 GMT, Andrew Koenig <ark@research.att.com> wrote:
>Siemel B. Naran <sbnaran@uiuc.edu> wrote:
>>I think that "*++i=c" may be equivalent to either of
>
>> ++i , *i=c ; // someone posted an example with this as the meaning
>> *i=c , ++i ; // principle behind this: do operations at end of statement
>No -- *++i=c is equivalent to the first example above only.
>(assuming that i is a pointer, which is the only built-in type
>that would cause the example to type-check)
>
>++i is defined as (i=i+1), so *++i=c means *(i=i+1)=c
>There is no problem with sequence points, because i is modified
>only once, and there is no question that what is being
>derefenced is (i=i+1), which is i after it was incremented.
So '*' is a sequence point?
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/20 Raw View
On 20 Sep 1999 18:14:48 GMT, Barry Margolin <barmar@bbnplanet.com> wrote:
>Siemel B. Naran <sbnaran@uiuc.edu> wrote:
>>The as-if rule allows optimizers to do whatever optimizations they please
>>as long as these optimizations do not change the observable behavior.
>Because of separate compilation, it's often not possible for a compiler to
>do as much optimization of user-defined operators. There may be some cases
>where the compiler can get close, but they're not common.
I think commonly used operators like op++ would be inline, and so the
optimization would be possible.
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/09/20 Raw View
In article <37E66DFF.D5393454@wizard.net>, James Kuyper
<kuyper@wizard.net> writes
>The standard includes a refusal to compile as one of the permitted
>kinds of undefined behavior. This is true of any undefined behavior, not
>just this particular case.
>
Well I cannot find any requirement for code to be compiled. AFAIK an
implementation can be a pure interpreter.
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: David R Tribble <david@tribble.com>
Date: 1999/09/20 Raw View
Christopher Eltschka wrote:
>
> Dirk van Deun wrote:
> > i = 5;
> > cerr << ++i << endl << --i << endl;
>
> This one is not OK: There is no sequence point between ++i
> and --i, so the behaviour is undefined. The most probable
> behaviours I'd expect would be
> - print 6 5 (evaluation left to right)
> - print 5 4 (evaluation right to left)
I thought that there was a sequence point prior to each call to
operator<<(). If so, the statement above is equivalent to:
i = 5;
cerr << ++i,
cerr << endl,
cerr << --i,
cerr << endl;
which should result in (well-defined) output of:
6
5
Sequence points do not occur, though, using operator<<() with
built-in primitive types:
i = 5;
int j;
j = j << ++i << i--; // undefined
-- David R. Tribble, david@tribble.com --
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/09/21 Raw View
On 20 Sep 99 23:47:45 GMT, David R Tribble <david@tribble.com> wrote:
: > > cerr << ++i << endl << --i << endl;
: I thought that there was a sequence point prior to each call to
: operator<<().
Yes.
: If so, the statement above is equivalent to:
:
: i = 5;
: cerr << ++i,
: cerr << endl,
: cerr << --i,
: cerr << endl;
No. Let's ignore the endl.
cout << ++i << --i;
cout.operator<<(++i).operator<<(--i);
operator<<(operator<<(cout, ++i), --i);
The parameters are all there and may be evaluated in any order. In
fact, the increment/decrement return lvalues and the lvalue to rvalue
conversion can be made at any time also.
++i;
--i;
operator<<(cout, i);
operator<<(cout, i);
Assume *i is lvalue to rvalue.
The requirements are ++i before *i1 before <<1,
--i before *i2 before <<2, <<1 before <<2.
++i *i1 <<1 --i *i2 <<2 6 5
++i *i1 --i <<1 *i2 <<2 6 5
++i *i1 --i *i2 <<1 <<2 6 5
++i --i *i1 <<1 *i2 <<2 5 5
++i --i *i1 *i2 <<1 <<2 5 5
++i --i *i2 *i1 <<1 <<2 5 5
--i ++i *i1 <<1 *i2 <<2 5 5
--i ++i *i1 *i2 <<1 <<2 5 5
--i ++i *i2 *i1 <<1 <<2 5 5
--i *i2 ++i *i1 <<1 <<2 5 4
I leave it to someone else to explain whether this is undefined
behavior allowing anything else to happen. The first one has a
sequence point between the modifications of i, but the others do
not.
See also a recent GotW on sequence points and exceptions.
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "James Kuyper Jr." <kuyper@wizard.net>
Date: 1999/09/21 Raw View
Francis Glassborow wrote:
>
> In article <37E66DFF.D5393454@wizard.net>, James Kuyper
> <kuyper@wizard.net> writes
> >The standard includes a refusal to compile as one of the permitted
> >kinds of undefined behavior. This is true of any undefined behavior, not
> >just this particular case.
> >
> Well I cannot find any requirement for code to be compiled. AFAIK an
> implementation can be a pure interpreter.
Of course. I normally try to use 'implementation' and 'translate' rather
than 'compiler' and 'compile' - the meanings aren't equivalent
(otherwise there'd be no point in the substitution), but they are
parallel. However, Mr. Belenov struck me as likely to be unfamiliar with
standardese, so I thought it safer to stick with the more ordinary
terms.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: ark@research.att.com (Andrew Koenig)
Date: 1999/09/21 Raw View
In article <slrn7ucvcn.nn3.sbnaran@localhost.localdomain>,
Siemel B. Naran <sbnaran@uiuc.edu> wrote:
>>++i is defined as (i=i+1), so *++i=c means *(i=i+1)=c
>>There is no problem with sequence points, because i is modified
>>only once, and there is no question that what is being
>>derefenced is (i=i+1), which is i after it was incremented.
>So '*' is a sequence point?
Does it matter?
--
Andrew Koenig, ark@research.att.com, http://www.research.att.com/info/ark
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/09/21 Raw View
In article <slrn7uaaln.pla.sbnaran@localhost.localdomain>,
sbnaran@uiuc.edu wrote:
> >But I disagree that the code is easy to follow. I find it obscure.
> Maybe that's because you're not used to it.
I'm tempted to say that if it takes getting used to, it is obscure:-).
> I've seen the following
> *i++ = *j++;
> and lots of people seem to accept it.
And a lot of others, like myself, don't:-).
On the other hand, I do see a large difference in the two. *p++ is
basically the same idiom as cin.get() -- it reads a value and advances
the current read position. It's C/C++'s answer to the FILE type in
Pascal:-). And reading sequential files *is* a common idiom in data
processing, regardless of the language. The only potential problem with
*p++ is thus the particular way it is expressed; this particular
expression is wide-spread enough (too wide-spread, IMHO) and well enough
documented that I would expect anyone even vaguely familiar with C or
C++ to recognize it as a sequential read. If this weren't the case,
then STL represents a horrid misuse of operator overloading, at least on
the level of iostream.
> It means "*i=*j" followed by
> "++i,++j".
No. It means (at the human level), i.put( j.get() ), or something along
those lines.
> That's why I find
> *++i = c;
> just as pleasing. Some of my old code still uses this style.
The use of preincrement is a much less wide-spread conventional idiom,
and I have some difficulty finding a general equivalent (in a range of
languages).
--
James Kanze mailto: James.Kanze@dresdner-bank.com
Conseils en informatique orient e objet/
Beratung in objekt orientierter Datenverarbeitung
Ziegelh ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Gabriel Dos_Reis <gdosreis@korrigan.inria.fr>
Date: 1999/09/21 Raw View
Francis Glassborow <francis@robinton.demon.co.uk> writes:
| In article <37E66DFF.D5393454@wizard.net>, James Kuyper
| <kuyper@wizard.net> writes
| >The standard includes a refusal to compile as one of the permitted
| >kinds of undefined behavior. This is true of any undefined behavior, not
| >just this particular case.
| >
| Well I cannot find any requirement for code to be compiled. AFAIK an
| implementation can be a pure interpreter.
Well, I would bet ISO 14882 does not require a C++ implementation to be
a compiler *but* I find the following in my copy:
1.4/8
---
... Implementations are requiredd to diagnose programs that use such
extensions that are ill-formed according to this International
Standard. Havind done so, however, they can compile and execute
^^^^^^^
such programs.
---
Was that an oversight?
--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 1999/09/21 Raw View
John Potter wrote:
>
> On 20 Sep 99 23:47:45 GMT, David R Tribble <david@tribble.com> wrote:
>
>
> I leave it to someone else to explain whether this is undefined
> behavior allowing anything else to happen. The first one has a
> sequence point between the modifications of i, but the others do
> not.
>
It's undefined behavior. The standard says that the value may not
be modified twice between sequence points for ANY ALLOWABLE ORDERING.
Since as you demonstrate, the compiler is free to peform both side
effects before calling the operator<< functions, this ordering shows
double modification and the expression yields undefined behavior.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James.Kanze@dresdner-bank.com
Date: 1999/09/21 Raw View
In article <slrn7u8jng.bhc.sbnaran@localhost.localdomain>,
sbnaran@uiuc.edu wrote:
>
> On 18 Sep 99 22:16:08 GMT, Jeff Rife <wevsr@nabs.net> wrote:
>
> >char *i = arr;
>
> >*++i=c; // Should set the arr[1]==c, thus arr[1]==0
>
> >SomeClass *scp = array;
>
> >*++scp=sc; // Should set the array[1]==sc, thus
array[1].x==10
> >Thus, it works if the pointer points to a built-in type, or if it
> >points to a UDT. In both cases, the *pointer* is a built-in type,
> >however.
> It works on your compiler. From my understanding of the standard, I
> don't think it is required to work. Is this correct?
Why not? I can't see any possible reason for it not to work either. No
undefined behavior has been invoked, and all of the operations are
defined.
--
James Kanze mailto: James.Kanze@dresdner-bank.com
Conseils en informatique orient e objet/
Beratung in objekt orientierter Datenverarbeitung
Ziegelh ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/09/21 Raw View
sbnaran@uiuc.edu (Siemel B. Naran) writes:
>On 20 Sep 1999 18:14:48 GMT, Barry Margolin <barmar@bbnplanet.com> wrote:
>>Siemel B. Naran <sbnaran@uiuc.edu> wrote:
>>>The as-if rule allows optimizers to do whatever optimizations they please
>>>as long as these optimizations do not change the observable behavior.
>>Because of separate compilation, it's often not possible for a compiler to
>>do as much optimization of user-defined operators. There may be some cases
>>where the compiler can get close, but they're not common.
>I think commonly used operators like op++ would be inline, and so the
>optimization would be possible.
Inlining a function does not change any semantic rules. In particular,
rules about sequence points are not changed. (Probably not all
compilers that right, however.)
--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/21 Raw View
On 20 Sep 99 23:47:45 GMT, David R Tribble <david@tribble.com> wrote:
>Christopher Eltschka wrote:
>> > cerr << ++i << endl << --i << endl;
>> This one is not OK: There is no sequence point between ++i
>> and --i, so the behaviour is undefined. The most probable
>> behaviours I'd expect would be
>I thought that there was a sequence point prior to each call to
>operator<<(). If so, the statement above is equivalent to:
>
> i = 5;
> cerr << ++i,
> cerr << endl,
> cerr << --i,
> cerr << endl;
>
>which should result in (well-defined) output of:
>
> 6
> 5
OK, I'm really confused about this issue of sequence points.
But I do know that Christopher's statement that the code is undefined
is right.
It makes sense with a parse tree.
cout << ++i << endl << --i << endl;
op<<
- -
- -
op<< endl
- -
- -
op<< --op
- - -
- - -
op<< endl i
- -
- -
cout ++op
-
-
i
The compiler may evaluate the sub-trees in any order, or simultaneously.
So it can evaluate "++i" first or "--i" first.
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Barry Margolin <barmar@bbnplanet.com>
Date: 1999/09/21 Raw View
In article <7s8e8e$7qo$1@engnews1.eng.sun.com>,
Steve Clamage <clamage@eng.sun.com> wrote:
>sbnaran@uiuc.edu (Siemel B. Naran) writes:
>
>>On 20 Sep 1999 18:14:48 GMT, Barry Margolin <barmar@bbnplanet.com> wrote:
>>>Siemel B. Naran <sbnaran@uiuc.edu> wrote:
>
>>>>The as-if rule allows optimizers to do whatever optimizations they please
>>>>as long as these optimizations do not change the observable behavior.
>
>>>Because of separate compilation, it's often not possible for a compiler to
>>>do as much optimization of user-defined operators. There may be some cases
>>>where the compiler can get close, but they're not common.
>
>>I think commonly used operators like op++ would be inline, and so the
>>optimization would be possible.
>
>Inlining a function does not change any semantic rules. In particular,
>rules about sequence points are not changed. (Probably not all
>compilers that right, however.)
That's not the issue. We're derived from the question of why built-in
operators don't have sequence points before the "call", so that they would
act like user-defined operators. I said that it was to allow optimization
of built-ins, implying that user-defined operators aren't amenable to such
optimizations. His point is that user-defined operators are also likely to
be inlined, so they could take advantage of the optimization capability as
well. So the distinction I made should not really be considered.
At this point, I think the only good answers to the original question is
"existing practice" and "compatibility with C". The semantics of the
built-in operators are basically derived from those of C, and in many cases
compilers share code generator modules for both C and C++ when processing
these expressions. They can take advantage of 40 years of experience in
optimizing arithmetic expressions. User-defined operators are specific to
C++, and they're simply defined as abbreviations for member function calls,
so it was simpler to define them in terms of member function semantics.
--
Barry Margolin, barmar@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: comeau@panix.com (Greg Comeau)
Date: 1999/09/21 Raw View
In article <slrn7ucvcn.nn3.sbnaran@localhost.localdomain> sbnaran@uiuc.edu writes:
>On 20 Sep 1999 16:30:45 GMT, Andrew Koenig <ark@research.att.com> wrote:
>>Siemel B. Naran <sbnaran@uiuc.edu> wrote:
>
>>>I think that "*++i=c" may be equivalent to either of
>>
>>> ++i , *i=c ; // someone posted an example with this as the meaning
>>> *i=c , ++i ; // principle behind this: do operations at end of statement
>
>>No -- *++i=c is equivalent to the first example above only.
>>(assuming that i is a pointer, which is the only built-in type
>>that would cause the example to type-check)
>>
>>++i is defined as (i=i+1), so *++i=c means *(i=i+1)=c
>>There is no problem with sequence points, because i is modified
>>only once, and there is no question that what is being
>>derefenced is (i=i+1), which is i after it was incremented.
>
>So '*' is a sequence point?
No, order of evaluation is not defined as sequence point.
All he's saying is that it's one valid interpretation and that
in this specific example the sequence point does not matter because
i is not used again.
- Greg
--
Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418-3214
Producers of Comeau C/C++ 4.2.38 -- NOTE 4.2.42 BETAS NOW AVAILABLE
Email: comeau@comeaucomputing.com / Voice:718-945-0009 / Fax:718-441-2310
*** WEB: http://www.comeaucomputing.com ***
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: comeau@panix.com (Greg Comeau)
Date: 1999/09/21 Raw View
In article <37E6BA31.781255E9@tribble.com> David R Tribble <david@tribble.com> writes:
>Christopher Eltschka wrote:
>>
>> Dirk van Deun wrote:
>> > i = 5;
>> > cerr << ++i << endl << --i << endl;
>>
>> This one is not OK: There is no sequence point between ++i
>> and --i, so the behaviour is undefined. The most probable
>> behaviours I'd expect would be
>> - print 6 5 (evaluation left to right)
>> - print 5 4 (evaluation right to left)
>
>I thought that there was a sequence point prior to each call to
>operator<<(). If so, the statement above is equivalent to:
>
> i = 5;
> cerr << ++i,
> cerr << endl,
> cerr << --i,
> cerr << endl;
>
>which should result in (well-defined) output of:
>
> 6
> 5
Why? How is this different than:
int foo(int);
int bar(int);
int x = foo(++i) + bar(--i);
>Sequence points do not occur, though, using operator<<() with
>built-in primitive types:
>
> i = 5;
> int j;
> j = j << ++i << i--; // undefined
- Greg
--
Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418-3214
Producers of Comeau C/C++ 4.2.38 -- NOTE 4.2.42 BETAS NOW AVAILABLE
Email: comeau@comeaucomputing.com / Voice:718-945-0009 / Fax:718-441-2310
*** WEB: http://www.comeaucomputing.com ***
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/22 Raw View
On 21 Sep 99 18:34:32 GMT, James.Kanze@dresdner-bank.com
>> It works on your compiler. From my understanding of the standard, I
>> don't think it is required to work. Is this correct?
>
>Why not? I can't see any possible reason for it not to work either. No
>undefined behavior has been invoked, and all of the operations are
>defined.
>From the rule that the compiler may rearrange builtin operators, I
deduced that "*++i=c" is equivalent to either of
*i=c; ++i;
++i; *i=c;
Later I thought that it could be equivalent to
++i; i=c; *i;
*i; i=c; ++i;
etc.
Evidently, I have no clue about this business of sequence points.
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/22 Raw View
On 21 Sep 99 18:34:58 GMT, Steve Clamage <clamage@eng.sun.com> wrote:
>sbnaran@uiuc.edu (Siemel B. Naran) writes:
>>>Because of separate compilation, it's often not possible for a compiler to
>>>do as much optimization of user-defined operators. There may be some cases
>>>where the compiler can get close, but they're not common.
>
>>I think commonly used operators like op++ would be inline, and so the
>>optimization would be possible.
>
>Inlining a function does not change any semantic rules. In particular,
>rules about sequence points are not changed. (Probably not all
>compilers that right, however.)
Yes, you are right about inline. However what I'm saying is that
inline lets the compiler do the as-if optimization more than it would
otherwise. For example, with op++ inline, the compiler may replace
while (begin!=end) *begin++=*end++;
with
while (begin!=end) { *begin=*end; ++begin,++end; }
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Valentin Bonnard <Bonnard.V@wanadoo.fr>
Date: 1999/09/22 Raw View
James Kuyper wrote:
> The standard includes a refusal to compile as one of the permitted
> kinds of undefined behavior.
IMO this is utter non-sens.
--
Valentin Bonnard
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/09/22 Raw View
sbnaran@uiuc.edu (Siemel B. Naran) writes:
> So '*' is a sequence point?
No, of course not. What are you so confused about? The expression ++p
causes p to be incremented, and its value is the incremented value, so
*++p addresses what the incremenetd pointer points at, just as if you
had written p[1]. You are assured that the actual modification of p
has happened when you encounter the next sequence point. OK?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Jeff Rife <wevsr@nabs.net>
Date: 1999/09/22 Raw View
Siemel B. Naran (sbnaran@uiuc.edu) wrote:
> > i = 5;
> > cerr << ++i << endl << --i << endl;
>
> This is undefined.
> The compiler may evaluate the 5 operands of the second statement
> cerr
> ++i
> endl
> --i
> endl
> in any order, and possibly even at the same time. In particular,
> the compiler may evaluate "++i" before "--i", or "--i" before "++i".
I completely understand why modifying a object more than once between
sequence points is undefined. But, as far as I can tell from the Standard,
this also invokes undefined behavior:
i = 5;
cerr << i << endl << --i << endl;
Is it undefined, and, if not, why not?
--
Jeff Rife |
19445 Saint Johnsbury Lane | http://www.nabs.net/Cartoons/OverTheHedge/BrokenInternet02.gif
Germantown, MD 20876-1610 |
Home: 301-916-8131 |
Work: 301-770-5800 Ext 5335 |
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/22 Raw View
On 21 Sep 1999 16:25:10 GMT, James.Kanze@dresdner-bank.com
>In article <slrn7uaaln.pla.sbnaran@localhost.localdomain>,
>I'm tempted to say that if it takes getting used to, it is obscure:-).
:)
>> That's why I find
>> *++i = c;
>> just as pleasing. Some of my old code still uses this style.
>
>The use of preincrement is a much less wide-spread conventional idiom,
>and I have some difficulty finding a general equivalent (in a range of
>languages).
Find space in the container for which 'i' is an iterator to hold one
more element, then set this new element equal to 'c'.
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/09/22 Raw View
On 20 Sep 99 23:46:31 GMT, sbnaran@uiuc.edu (Siemel B. Naran) wrote:
: On 20 Sep 1999 16:30:45 GMT, Andrew Koenig <ark@research.att.com> wrote:
: >Siemel B. Naran <sbnaran@uiuc.edu> wrote:
:
: >>I think that "*++i=c" may be equivalent to either of
: >
: >> ++i , *i=c ; // someone posted an example with this as the meaning
: >> *i=c , ++i ; // principle behind this: do operations at end of statement
:
: >No -- *++i=c is equivalent to the first example above only.
: >(assuming that i is a pointer, which is the only built-in type
: >that would cause the example to type-check)
: >
: >++i is defined as (i=i+1), so *++i=c means *(i=i+1)=c
: >There is no problem with sequence points, because i is modified
: >only once, and there is no question that what is being
: >derefenced is (i=i+1), which is i after it was incremented.
:
: So '*' is a sequence point?
Well, no. Let's see if we can make non^H^H^Hsense of this.
In C, ++p returns the new value of p and it is an rvalue.
int i[2];
int* p = i;
*++p = 5;
Sure enough, i[1] is 5 but the code is:
int* reg = p + 1;
*reg = 5;
p = reg;
That's ok because the rvalue which was dereferenced was p + 1.
But, in C++, ++p returns the new value of p and it is an lvalue. We
know that the only lvalue that it can return is p, so p must have the
new value. There must be a sequence point in that prefix ++. Let's
prove it with an absurdity which also covers assignment and its lvalue.
int i[2];
int* p(i);
int** pp;
int*** ppp;
***(ppp = &(pp = &++p)) = 5;
Sure enough, all of the variables have the expected values, but the
code is:
int* reg = p + 1;
*reg = 5;
ppp = &pp;
pp = &p
p = reg;
Totally ignored all of the semantics explained in the standard. Let's
try to catch them.
int i[3];
int* p(i);
++ ++ p;
I didn't get the expected results, in fact I didn't get any output. The
code was:
<self mail comp-std-c++@moderators.isc.org
-s 'Look at the dumb thing I did'
Fortunately, it seems to have been lost along with my prior ramblings
on this subject ;-)
That damned undefined behavior, I can't determine if ++p really
returns an lvalue any other way. As-if rules!
So ++p returns the new value of p and *++p will work regardless of
when the new value actually gets placed in p. C++ is a bit trickier
than C because we get these lvalues which may not be lvalues that
get converted to rvalues. In the absence of a sequence point, it
can do whatever it wants as long as we can't tell.
The bottom line is that the lvalues from prefix ++/-- and = are a
crock of brown stuff other than allowing taking the address. Any
other use is undefined behavior. An interesting side effect is
that the STL requires an operator= which returns a reference although
there is no way that it can be used (T might be builtin).
This helped me, hope it helps you.
John
P.S. Peanutbutter is brown and comes in a crock. In this case it
seems to be crunchy. :)
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/09/22 Raw View
On 21 Sep 1999 15:43:13 GMT, ark@research.att.com (Andrew Koenig) wrote:
: In article <slrn7ucvcn.nn3.sbnaran@localhost.localdomain>,
: Siemel B. Naran <sbnaran@uiuc.edu> wrote:
: > So '*' is a sequence point?
: Does it matter?
Maybe.
struct S { S** p; };
S s[3];
S* q(s);
s[1].p = &q;
++*(++q)->p;
Modifies q twice with a (*) sequence point between.
But, does it matter?
John
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Pete Becker <petebecker@acm.org>
Date: 1999/09/18 Raw View
James Kuyper wrote:
>
> "Siemel B. Naran" wrote:
> >
> > On 16 Sep 1999 22:07:43 GMT, Hyman Rosen <hymie@prolifics.com> wrote:
> > >sbnaran@uiuc.edu (Siemel B. Naran) writes:
> >
> > >> But why does G++ under Linux give 10?
> > >
> > >It's undefined behavior, so asking why is silly.
> >
> > It's not silly. I expect to see either "9" or "11", not "10". It
> > is reasonable to ask why, especially if you are interested in how
> > your compiler compiles.
>
> But that's more properly a question about compiler technology, than
> anything that's relevant to the standard. The standard allows it to have
> any value whatsoever; the method the compiler uses to get that value is
> irrelevant.
>
The standard is less restrictive than that: the effect of executing code
containing that statement is undefined. It is not required to produce a
value at all. It could simply crash, and still conform to the language
definition.
--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Jeff Rife <wevsr@nabs.net>
Date: 1999/09/18 Raw View
Siemel B. Naran (sbnaran@uiuc.edu) wrote:
> In cases like "*++i=c" I don't agree with you. I find this code
> easy to parse. Yet this code won't work if 'i' is a builtin type
> like "SomeClass *".
I don't know exactly what you meant to say, but the following seems
to compile just fine on my compiler, which, I know, doesn't mean anything,
but still, I can't find any fault with it WRT the standard....
/////////////////////////////////////////////////////////////
class SomeClass
{
public:
SomeClass(int x_init = 0) : x(x_init) {}
int x;
};
#include <stdio.h>
int main()
{
char arr[10] = "Hello";
char *i = arr;
char c = '\0';
*++i=c; // Should set the arr[1]==c, thus arr[1]==0
printf("%s\n", arr); // and this should output "H\n"
SomeClass array[10];
SomeClass *scp = array;
SomeClass sc(10);
*++scp=sc; // Should set the array[1]==sc, thus array[1].x==10
printf("%d\n", array[1].x);
return 0;
}
/////////////////////////////////////////////////////////////
The output is the expected:
H
10
Thus, it works if the pointer points to a built-in type, or if it points
to a UDT. In both cases, the *pointer* is a built-in type, however.
I wasn't going to go to the effort to create a "smart pointer" type
that has operator* and operator++ defined for it, but I don't see why
it wouldn't work for that, too, with reasonable definitions.
--
Jeff Rife | Coach: How's life, Norm?
19445 Saint Johnsbury Lane |
Germantown, MD 20876-1610 | Norm: Not for the squeamish, Coach.
Home: 301-916-8131 |
Work: 301-770-5800 Ext 5335 |
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/19 Raw View
On 18 Sep 99 22:16:08 GMT, Jeff Rife <wevsr@nabs.net> wrote:
>char *i = arr;
>*++i=c; // Should set the arr[1]==c, thus arr[1]==0
>SomeClass *scp = array;
>*++scp=sc; // Should set the array[1]==sc, thus array[1].x==10
>Thus, it works if the pointer points to a built-in type, or if it points
>to a UDT. In both cases, the *pointer* is a built-in type, however.
It works on your compiler. From my understanding of the standard, I
don't think it is required to work. Is this correct?
--
--------------
siemel b naran
--------------
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/09/19 Raw View
sbnaran@uiuc.edu (Siemel B. Naran) writes:
>On 17 Sep 99 20:35:57 GMT, Steve Clamage <clamage@eng.sun.com> wrote:
>>In any event, it's best to avoid code that modifies an object more
>>than once in a single expression. Even when the code happens to
>>have defined behavior, it is hard for human readers to understand.
>In cases like "i=++i+1" I agree with you. This code is hard to parse.
>I find this better "++i; i+=1;".
>In cases like "*++i=c" I don't agree with you. I find this code
>easy to parse. Yet this code won't work if 'i' is a builtin type
>like "SomeClass *".
But that last example doesn't necessarily modify the same object
twice. It depends on what *i refers to.
And what do you mean by "it doesn't work" when 'i' has a class type?
Since class types don't have predefined ++ and * operators, the
code is equivalent to
(i.operator++()).operator*() = c;
Since there is a sequence point at each function call, the
order of operations is well-defined. (Depending on the return
type of operator*, the assignment might also be a function.)
But I disagree that the code is easy to follow. I find it obscure.
--
Steve Clamage, stephen.clamage@sun.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/20 Raw View
On 19 Sep 1999 16:29:42 GMT, Steve Clamage <clamage@eng.sun.com> wrote:
>sbnaran@uiuc.edu (Siemel B. Naran) writes:
>>In cases like "*++i=c" I don't agree with you. I find this code
>>easy to parse. Yet this code won't work if 'i' is a builtin type
>>like "SomeClass *".
>
>But that last example doesn't necessarily modify the same object
>twice. It depends on what *i refers to.
I think that "*++i=c" may be equivalent to either of
++i , *i=c ; // someone posted an example with this as the meaning
*i=c , ++i ; // principle behind this: do operations at end of statement
As there is more than one logical result, the result is undefined.
The compiler may refuse to compile the code, do an abort at runtime,
do either of the above two equivalents, or do anything else.
>And what do you mean by "it doesn't work" when 'i' has a class type?
>Since class types don't have predefined ++ and * operators, the
>code is equivalent to
> (i.operator++()).operator*() = c;
>Since there is a sequence point at each function call, the
>order of operations is well-defined. (Depending on the return
>type of operator*, the assignment might also be a function.)
I'm confused by this paragraph. I said, "it won't work if 'i' is a
builtin type".
>But I disagree that the code is easy to follow. I find it obscure.
Maybe that's because you're not used to it. I've seen the following
*i++ = *j++;
and lots of people seem to accept it. It means "*i=*j" followed by
"++i,++j".
That's why I find
*++i = c;
just as pleasing. Some of my old code still uses this style.
--
--------------
siemel b naran
--------------
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/09/20 Raw View
sbnaran@uiuc.edu (Siemel B. Naran) writes:
>I think that "*++i=c" may be equivalent to either of
> ++i , *i=c ; // someone posted an example with this as the meaning
> *i=c , ++i ; // principle behind this: do operations at end of statement
No. The update of i in memory can occur at any time up to the
next sequence point, but *++i can only mean to dereference the
result of adding 1 to i. The original could be compiled as
*(i+1)=c, ++i
which gives the same result as your first line if i doesn't point
to itself. If i does point to itself, the expression has undefined
semantics.
--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/09/20 Raw View
"Siemel B. Naran" wrote:
>
> On 17 Sep 99 20:35:57 GMT, Steve Clamage <clamage@eng.sun.com> wrote:
> >sbnaran@uiuc.edu (Siemel B. Naran) writes:
>
> >>It is mysterious/bizarre that the result of builtin operators and
> >>user defined operators are different.
> >
> >Perhaps that is an argument against using overloaded operators.
>
> Funny and interesting.
>
> >In any event, it's best to avoid code that modifies an object more
> >than once in a single expression. Even when the code happens to
> >have defined behavior, it is hard for human readers to understand.
>
> In cases like "i=++i+1" I agree with you. This code is hard to parse.
> I find this better "++i; i+=1;".
>
> In cases like "*++i=c" I don't agree with you. I find this code
> easy to parse. Yet this code won't work if 'i' is a builtin type
> like "SomeClass *".
Unless (i+1) points back to i, the behaviour is well defined:
i is modified once, and *++i is modified once.
The result of "++i" is one more than the original value of i
(it doesn't matter when the value of i _itself_ is incremented).
The basic operations are
(1) tmp1 = i
(2) tmp2 = tmp1 + 1
(3) i = tmp2
(4) tmp3 = tmp1 + 1
(5) *tmp3 = c
Now, the possible actions are:
(1,2,3,4,5), (1,2,4,3,5), (1,2,4,5,3), (1,4,2,3,5), (1,4,2,5,3),
(1,4,5,2,3).
Also, the compiler can take advantage of the fact that the value
of tmp2 and tmp3 is the same. And it can take advantage of the
fact that there's often an instruction doing (1,2,3) without
using any temp register/memory. And it may take advantage that
after (3), i contains the same value that belongs into tmp3.
Which would result in "inc i; *i = c;" (_not_ in "*i=c; inc i;").
However, all this doesn't modify the observable behaviour,
unless *tmp3 and i are the same (in which case the behaviour
is undefined anyway).
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/09/20 Raw View
"Siemel B. Naran" wrote:
>
> On 16 Sep 99 09:03:53 GMT, Christopher Eltschka
>
> >> i = 5;
> >> cerr << ++i + --i << endl;
> >
> >Same problem here. "+" doesn't introduce a sequence point
> >as well, so again this is undefined. Most probable outcomes:
> >- print 11 (left to right)
> >- print 9 (right to left)
>
> But why does G++ under Linux give 10?
Because g++ has a good optimizer ;-)
Possibly the optimizer happened to move the
incrementing/decrementing close to each other during optimizing,
and then found that ++ and -- cancel each other and removed them.
That's just a guess, of course.
In any case, whatever it did, it's correct to do so. That's
the point of undefined behaviour.
[...]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: ark@research.att.com (Andrew Koenig)
Date: 1999/09/20 Raw View
In article <slrn7uaaln.pla.sbnaran@localhost.localdomain>,
Siemel B. Naran <sbnaran@uiuc.edu> wrote:
>I think that "*++i=c" may be equivalent to either of
> ++i , *i=c ; // someone posted an example with this as the meaning
> *i=c , ++i ; // principle behind this: do operations at end of statement
>As there is more than one logical result, the result is undefined.
No -- *++i=c is equivalent to the first example above only.
(assuming that i is a pointer, which is the only built-in type
that would cause the example to type-check)
++i is defined as (i=i+1), so *++i=c means *(i=i+1)=c
There is no problem with sequence points, because i is modified
only once, and there is no question that what is being
derefenced is (i=i+1), which is i after it was incremented.
--
Andrew Koenig, ark@research.att.com, http://www.research.att.com/info/ark
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/17 Raw View
On 17 Sep 99 04:35:49 GMT, Ron Natalie <ron@sensor.com> wrote:
>Without the interior sequence points, you are right, you do not know when
>the side effect occurs, which could be anytime up until the next
>sequence point (end of the full expression).
Doesn't "end of full expression" mean at the semicolon?
So maybe you should have said "end of sub-expression"?
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 1999/09/17 Raw View
"Siemel B. Naran" wrote:
> If 'x' is a builtin type, then the above is equal to either of
> ++x , x=x+1 ;
> x=x+1 , ++x ;
> So the result is "2" or "3".
>
No, the result is undefined behavior. The compiler is not
constrained to yield a useful value at all.
If you really want to know what happens:
incl -4(%ebp) ; i++
decl -4(%ebp) ; i--
movl -4(%ebp),%eax ; A register = i
movl -4(%ebp),%edx ; D register = i
addl %edx,%eax ; A reg = D reg + Areg
A register now has the value of the expression.
It applies both side effects prior to retrieving the
values for the add.
Now you know, but you dare not use that, because it may
not be true the next time you run the compiler. The
behavior is trully undefined.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 1999/09/17 Raw View
"Siemel B. Naran" wrote:
>
> On 17 Sep 99 04:35:49 GMT, Ron Natalie <ron@sensor.com> wrote:
>
> >Without the interior sequence points, you are right, you do not know when
> >the side effect occurs, which could be anytime up until the next
> >sequence point (end of the full expression).
>
> Doesn't "end of full expression" mean at the semicolon?
> So maybe you should have said "end of sub-expression"?
>
Nope, I meant the full expression (which in this case means at the ";"),
since the first have of that sentence says "without interior sequence
points."
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Barry Margolin <barmar@bbnplanet.com>
Date: 1999/09/17 Raw View
In article <slrn7u3g58.daa.sbnaran@localhost.localdomain>,
Siemel B. Naran <sbnaran@uiuc.edu> wrote:
>It is mysterious/bizarre that the result of builtin operators and
>user defined operators are different.
There are generally more opportunities for optimization of built-in
operators, because they frequently correspond closely with machine
instructions. C programmers expect them to generate very efficient code
that takes advantage of this correlation. But when using user-defined
operators, they expect their functions to be called; they're just using the
operator overload syntax as a shorthand.
--
Barry Margolin, barmar@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Mike Austin <cut-m.austin@ix.netcom.com>
Date: 1999/09/17 Raw View
If it's undefined, shouldn't it be an error??? The compiler doesn't try to
guess ambiguous function calls, so why should it try on operators? Something
like that would be very hard to debug.
Mike
Ron Natalie wrote:
> "Siemel B. Naran" wrote:
>
> > If 'x' is a builtin type, then the above is equal to either of
> > ++x , x=x+1 ;
> > x=x+1 , ++x ;
> > So the result is "2" or "3".
> >
> No, the result is undefined behavior. The compiler is not
> constrained to yield a useful value at all.
>
> If you really want to know what happens:
>
> incl -4(%ebp) ; i++
> decl -4(%ebp) ; i--
> movl -4(%ebp),%eax ; A register = i
> movl -4(%ebp),%edx ; D register = i
> addl %edx,%eax ; A reg = D reg + Areg
>
> A register now has the value of the expression.
>
> It applies both side effects prior to retrieving the
> values for the add.
>
> Now you know, but you dare not use that, because it may
> not be true the next time you run the compiler. The
> behavior is trully undefined.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 1999/09/17 Raw View
Mike Austin wrote:
>
> If it's undefined, shouldn't it be an error???
Nope, the compiler is under no obligation to check for or issue
warnings for undefined behavior.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: James Kuyper <kuyper@wizard.net>
Date: 1999/09/17 Raw View
"Siemel B. Naran" wrote:
>
> On 16 Sep 1999 22:07:43 GMT, Hyman Rosen <hymie@prolifics.com> wrote:
> >sbnaran@uiuc.edu (Siemel B. Naran) writes:
>
> >> But why does G++ under Linux give 10?
> >
> >It's undefined behavior, so asking why is silly.
>
> It's not silly. I expect to see either "9" or "11", not "10". It
> is reasonable to ask why, especially if you are interested in how
> your compiler compiles.
But that's more properly a question about compiler technology, than
anything that's relevant to the standard. The standard allows it to have
any value whatsoever; the method the compiler uses to get that value is
irrelevant.
...
> It is mysterious/bizarre that the result of builtin operators and
> user defined operators are different.
Not really - user-defined operators use function-call semantics, which
creates extra sequence points that don't occur in the built-in case.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/09/17 Raw View
sbnaran@uiuc.edu (Siemel B. Naran) writes:
>On 16 Sep 1999 22:07:43 GMT, Hyman Rosen <hymie@prolifics.com> wrote:
>>sbnaran@uiuc.edu (Siemel B. Naran) writes:
>>> But why does G++ under Linux give 10?
>>
>>It's undefined behavior, so asking why is silly.
>It's not silly. I expect to see either "9" or "11", not "10".
But that expectation is not justified. "Undefined behavior" means
the standard places NO requirements on the implementation. Any
result, including "-1", "42", a refusal to compile, or a run-time
abort, is allowed.
>See the post by Steve Clamage. He gives an example like this
> Int x(1);
> x = ++x + 1;
> std::cout << x;
>If 'Int' is a user-defined class, then the above is equivalent to
> operator=(x,operator+(operator++(x),1));
>which is well defined. The result is "3".
>If 'x' is a builtin type, then the above is equal to either of
> ++x , x=x+1 ;
> x=x+1 , ++x ;
>So the result is "2" or "3".
No, the result is undefined. Refer to sections 1.3.12 and 1.9 in
the C++ standard.
>It is mysterious/bizarre that the result of builtin operators and
>user defined operators are different.
Perhaps that is an argument against using overloaded operators.
In any event, it's best to avoid code that modifies an object more
than once in a single expression. Even when the code happens to
have defined behavior, it is hard for human readers to understand.
--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Barry Margolin <barmar@bbnplanet.com>
Date: 1999/09/17 Raw View
In article <37E2880B.59AE0EAD@ix.netcom.com>,
Mike Austin <cut-m.austin@ix.netcom.com> wrote:
>If it's undefined, shouldn't it be an error??? The compiler doesn't try to
>guess ambiguous function calls, so why should it try on operators? Something
>like that would be very hard to debug.
The compiler can't always detect the conflicts. E.g.
p = &i;
i = ++(*p);
--
Barry Margolin, barmar@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/09/17 Raw View
Mike Austin <cut-m.austin@ix.netcom.com> writes:
>If it's undefined,
[ meaning multiple modifications of an object between sequence points ]
>shouldn't it be an error???
It is an error.
"Undefined behavior" means, among other things, that the compiler
is allowed to detect the error, but is not required to. Usually when
"undefined behavior" is specified, it is because it is too difficult
or even impossible to detect the error. (Sometimes behavior is left
undefined to allow for implementations to provide useful defined
behavior which might not be available on all systems.)
>The compiler doesn't try to
>guess ambiguous function calls, so why should it try on operators? Something
>like that would be very hard to debug.
The cases are not comparable. In the case of a function call, the
compiler must always inspect all visible function declarations to
determine which one to call. Either there is exactly one function
that is a best match and can be called, or there is not.
Consider this complete translation unit:
int foo(int* p, int* q) { return ++*p + ++*q; }
If p and q point to the same object, the result of calling the
function is undefined, but it is impossible to know at compile
time whether that is the case.
How about this:
int a, b, c, d, e;
...
a = (b>=c) ? ++d + ++e : (b<c) ? ++d - ++e : --d + --d;
At first glance it appears that d and e are each modified
more than once, but control flow analysis would reveal that
1. the three sections of code are mutually exclusive, so that
an increment of d or e can happen at most once;
2. the third case which looks like a clear violation cannot
ever be executed.
Should the standard require all compilers to perform this analysis?
How about this:
double x;
int k;
...
if( ::cos(x) > 1.0 ) k = ++k;
The global cos function is reserved, and cannot be replaced by
user code. The specification for the fucntion is such that it
cannot return a value greater than 1.0, so what looks like
invalid code is not an error.
Should the standard require all compilers to be this smart?
--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/09/17 Raw View
In article <37E2880B.59AE0EAD@ix.netcom.com>, Mike Austin <cut-
m.austin@ix.netcom.com> writes
>If it's undefined, shouldn't it be an error??? The compiler doesn't try to
>guess ambiguous function calls, so why should it try on operators? Something
>like that would be very hard to debug.
It is an error but one that the compiler is not required to diagnose (In
general it cannot because of, among other things, the aliasing problem)
Of course compilers could do a better job, just because it is not
required does not mean that they are not allowed to be helpful:)
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Barry Margolin <barmar@bbnplanet.com>
Date: 1999/09/17 Raw View
In article <37E283AA.316237F1@wizard.net>,
James Kuyper <kuyper@wizard.net> wrote:
>"Siemel B. Naran" wrote:
>>
>> On 16 Sep 1999 22:07:43 GMT, Hyman Rosen <hymie@prolifics.com> wrote:
>> >sbnaran@uiuc.edu (Siemel B. Naran) writes:
>>
>> >> But why does G++ under Linux give 10?
>> >
>> >It's undefined behavior, so asking why is silly.
>>
>> It's not silly. I expect to see either "9" or "11", not "10". It
>> is reasonable to ask why, especially if you are interested in how
>> your compiler compiles.
>
>But that's more properly a question about compiler technology, than
>anything that's relevant to the standard. The standard allows it to have
>any value whatsoever; the method the compiler uses to get that value is
>irrelevant.
His question *was* about the compiler. His question was specific to "G++
under Linux". It's true that this newsgroup is about the standard, but
it was clearly just a side comment out of curiosity.
Just because something is allowed by the standard doesn't mean that it's
reasonable or even likely. When referring to undefined consequences we
often jokingly say that it could launch a nuclear strike; however, although
the standard allows this, common sense and the principle of least
astonishment do not.
--
Barry Margolin, barmar@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/09/17 Raw View
In article <slrn7u3g58.daa.sbnaran@localhost.localdomain>, Siemel B.
Naran <sbnaran@uiuc.edu> writes
>If 'x' is a builtin type, then the above is equal to either of
> ++x , x=x+1 ;
> x=x+1 , ++x ;
>So the result is "2" or "3".
You might wish it so, but it isn't there is no sequence point so the
side-effects of evaluation happen at some unspecified time before the
next sequence point. While evaluation must be (as-if) sequential, there
is no such requirement on the side-effects. evaluation of the complete
expression requires two writes to x that might be interlaced (unless int
is an atomic operation on the underlying hardware). On some hardware
this could cause all sorts of problems (granted rare, but this is why
the result is undefined rather than just being unspecified)
>
>It is mysterious/bizarre that the result of builtin operators and
>user defined operators are different.
>
>
>On the other hand, I prefer not to have to deal with code like
>"x=++x+1" anyway as it is somewhat hard for humans to parse.
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/09/17 Raw View
In article <slrn7u1161.bsm.sbnaran@localhost.localdomain>, Siemel B.
Naran <sbnaran@uiuc.edu> writes
>
>I think this should always print "6 5".
>
>However, I recall a bizarre thread that said that operators for builtin
>types are different in that the side effects may occur at the end of
>the full expression. Hence the above would be the same as
> cerr << i << endl, cerr << i << endl , ++i , --i;
>And so the output may be "5 5".
No. sequence points must be respected and comma in this context is the
sequence operator.
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/09/17 Raw View
Mike Austin <cut-m.austin@ix.netcom.com> writes:
> If it's undefined, shouldn't it be an error??? The compiler doesn't try to
> guess ambiguous function calls, so why should it try on operators? Something
> like that would be very hard to debug.
The compiler is free to warn about the situation if it detects it,
but the Standard can not mandate that such an error be detected,
since such information is undecidable. That is, suppose I have
void f(int &a, int &b) { cout << ++a << "," << --b << endl; }
Then if I have
int i, j;
It's perfectly OK for me to call f(i, j), but undefined behavior for
me to call f(i, i). And since the definition of f can be in a different
compilation unit than its use, all bets are off.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/18 Raw View
On 17 Sep 1999 19:28:00 GMT, Barry Margolin <barmar@bbnplanet.com> wrote:
>Siemel B. Naran <sbnaran@uiuc.edu> wrote:
>>It is mysterious/bizarre that the result of builtin operators and
>>user defined operators are different.
>
>There are generally more opportunities for optimization of built-in
>operators, because they frequently correspond closely with machine
>instructions. C programmers expect them to generate very efficient code
>that takes advantage of this correlation. But when using user-defined
>operators, they expect their functions to be called; they're just using the
>operator overload syntax as a shorthand.
The as-if rule allows optimizers to do whatever optimizations they please
as long as these optimizations do not change the observable behavior.
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/18 Raw View
On 17 Sep 1999 19:28:01 GMT, Mike Austin <cut-m.austin@ix.netcom.com> wrote:
>If it's undefined, shouldn't it be an error??? The compiler doesn't try to
>guess ambiguous function calls, so why should it try on operators? Something
>like that would be very hard to debug.
The compiler can't detect these errors for the general case, eg.
int x = ++i + ++j;
What if both 'i' and 'j' are references to 'a'.
But where the compiler can detect the error, an error message would be
most welcome. But is it really worth it to put this special case code
into the compiler?
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/18 Raw View
On 17 Sep 99 20:35:57 GMT, Steve Clamage <clamage@eng.sun.com> wrote:
>sbnaran@uiuc.edu (Siemel B. Naran) writes:
>>It is mysterious/bizarre that the result of builtin operators and
>>user defined operators are different.
>
>Perhaps that is an argument against using overloaded operators.
Funny and interesting.
>In any event, it's best to avoid code that modifies an object more
>than once in a single expression. Even when the code happens to
>have defined behavior, it is hard for human readers to understand.
In cases like "i=++i+1" I agree with you. This code is hard to parse.
I find this better "++i; i+=1;".
In cases like "*++i=c" I don't agree with you. I find this code
easy to parse. Yet this code won't work if 'i' is a builtin type
like "SomeClass *".
--
--------------
siemel b naran
--------------
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Pete Becker <petebecker@acm.org>
Date: 1999/09/18 Raw View
"Siemel B. Naran" wrote:
>
> See the post by Steve Clamage. He gives an example like this
>
> Int x(1);
> x = ++x + 1;
> std::cout << x;
>
> If 'Int' is a user-defined class, then the above is equivalent to
> operator=(x,operator+(operator++(x),1));
> which is well defined. The result is "3".
>
> If 'x' is a builtin type, then the above is equal to either of
> ++x , x=x+1 ;
> x=x+1 , ++x ;
> So the result is "2" or "3".
Not according to the language definition. The code produces undefined
behavior. Most compilers will produce 2 or 3, but that's a statement
about compilers, not about the language.
--
Pete Becker
Dinkumware, Ltd.
http://www.dinkumware.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/09/16 Raw View
In article <7rp3ik$3mk$1@mach.vub.ac.be>, Dirk van Deun
<dvandeun@vub.ac.be> writes
> int i = 5;
> cerr << ++i << endl, cerr << --i << endl;
the comma is a sequence point so 6 5 is correct
> i = 5;
> cerr << ++i << endl << --i << endl;
You now have two writes to i between sequence points, assuming that the
<< is not a function call and you have undefined behaviour. However if
<< is provided by an operator function you have an order of evaluation
problem.
> i = 5;
> cerr << ++i + --i << endl;
And now you are in deep trouble because you certainly have two writes to
i between sequence points which gives undefined behaviour.
>
>Compiled with egcs 2.91.66, this gives 6 5 6 5 11 under Solaris and
>6 5 5 4(!) 10 under Linux. I did expect 5 5 5 5 10. Is this
>behaviour defined exactly anyway ?
>
>(I saw a program segfault under one OS while it worked fine under
>the other because of pre-increment combinations on iterators...)
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/16 Raw View
On 16 Sep 99 04:26:54 GMT, Dirk van Deun <dvandeun@vub.ac.be> wrote:
> int i = 5;
> cerr << ++i << endl, cerr << --i << endl;
I think this should always print "6 5".
However, I recall a bizarre thread that said that operators for builtin
types are different in that the side effects may occur at the end of
the full expression. Hence the above would be the same as
cerr << i << endl, cerr << i << endl , ++i , --i;
And so the output may be "5 5".
> i = 5;
> cerr << ++i << endl << --i << endl;
This is undefined.
The compiler may evaluate the 5 operands of the second statement
cerr
++i
endl
--i
endl
in any order, and possibly even at the same time. In particular,
the compiler may evaluate "++i" before "--i", or "--i" before "++i".
So the output may be "6 5" or "5 4".
I guess the compiler can go the bizarre route again and performs all
builtin operations at the end of the full expression. Hence the
result may also be "5 5".
The compiler may also refuse to compile code that is undefined.
> i = 5;
> cerr << ++i + --i << endl;
This is undefined.
In the expression "++i + --i" the compiler may evaluate "++i" first
or "--i" first. If "++i" first, then the result is 6+5 or 11. If
"--i" first, then the result is 5+4 or 9. So we see either "11" or
"9".
If the compiler performs all builtin operations at the end of the
full expression, then the result is "10"
cerr << i + i << endl , ++i , --i ;
The compiler may also refuse to compile code that is undefined.
>Compiled with egcs 2.91.66, this gives 6 5 6 5 11 under Solaris and
>6 5 5 4(!) 10 under Linux. I did expect 5 5 5 5 10. Is this
>behaviour defined exactly anyway ?
On Intel Linux I get
6 5 5 4 10
On Intel Linux using a class Int I get
6 5 5 4 9
class Int
{
public:
explicit Int(int i) : i(i) { }
Int& operator++() { ++i; return *this; }
Int& operator--() { --i; return *this; }
friend Int operator+(Int lhs, Int rhs) { return Int(lhs.i+rhs.i); }
friend ostream& operator<<(ostream& os, Int i) { return os << i.i; }
private:
int i;
};
>(I saw a program segfault under one OS while it worked fine under
>the other because of pre-increment combinations on iterators...)
Since the behaviour is undefined, I guess this is a valid result
too.
--
--------------
siemel b naran
--------------
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/09/16 Raw View
sbnaran@uiuc.edu (Siemel B. Naran) writes:
>On 16 Sep 99 04:26:54 GMT, Dirk van Deun <dvandeun@vub.ac.be> wrote:
>> int i = 5;
>> cerr << ++i << endl, cerr << --i << endl;
>I think this should always print "6 5".
>However, I recall a bizarre thread that said that operators for builtin
>types are different in that the side effects may occur at the end of
>the full expression. Hence the above would be the same as
> cerr << i << endl, cerr << i << endl , ++i , --i;
>And so the output may be "5 5".
The effects are determined by sequence points. The end of a full
expresssion is a sequence point, but a comma-expression also has
a sequence point at the comma. At a sequence point, all side
effects must be complete before executing the code that
follows. In the example, the comma ensures that the output
will be "6 5".
--
Steve Clamage, stephen.clamage@sun.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/16 Raw View
On 16 Sep 99 09:03:53 GMT, Christopher Eltschka
>> i = 5;
>> cerr << ++i + --i << endl;
>
>Same problem here. "+" doesn't introduce a sequence point
>as well, so again this is undefined. Most probable outcomes:
>- print 11 (left to right)
>- print 9 (right to left)
But why does G++ under Linux give 10?
>(Any case I've forgotten?)
There is a special rule about builtin operators, that IMHO should not be.
--
--------------
siemel b naran
--------------
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/09/16 Raw View
sbnaran@uiuc.edu (Siemel B. Naran) writes:
>On 16 Sep 99 09:03:53 GMT, Christopher Eltschka
>
>>> i = 5;
>>> cerr << ++i + --i << endl;
>>
>>Same problem here. "+" doesn't introduce a sequence point
>>as well, so again this is undefined. Most probable outcomes:
>>- print 11 (left to right)
>>- print 9 (right to left)
>But why does G++ under Linux give 10?
Because the results are undefined? There's no way to predict
when the side effects occur, and a variety of results are
plausible.
That is, the expresion ++i yields the value of i+1, but
actually incrementing the value of i in memory can occur
at any time up to the next sequence point.
>>(Any case I've forgotten?)
>There is a special rule about builtin operators, that IMHO should not be.
What special rule? The only "special rule" I can think of is
that most built-in operators do not establish a sequence point,
but an overloaded operator is a function, which does.
Example:
int x;
T y; // T is some type
...
x = y + x++;
The last line attempts to modify x twice in one expression.
If type T is an arithmetic type, the built-in ++, +, and = are
used. None of the operators establishes a sequence point. In
that case, the results are undefined.
Now suppose T is a class type, and there is a corresponding operator+
that yields a value that can be assigned to an int. The code is
equivalent to
x = operator+(y, x++);
After evaluating "y" and "x++" there is a sequence point before
calling the function. The side effect of incrementing x in memory
is completed before the function call, and the only remaining side
effect is the final assignment of the return value to x. The results
are fully defined.
Details are in section 1.9 of the C++ standard.
--
Steve Clamage, stephen.clamage@sun.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/09/16 Raw View
sbnaran@uiuc.edu (Siemel B. Naran) writes:
> >> i = 5;
> >> cerr << ++i + --i << endl;
> But why does G++ under Linux give 10?
It's undefined behavior, so asking why is silly.
> There is a special rule about builtin operators, that IMHO should not be.
What is this mysterious rule you're talking about?
I don't think any such rule exists.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/09/17 Raw View
Robert Kolter <kolter@student.uni-kl.de> writes:
>Dirk van Deun schrieb:
>> int i = 5;
>> cerr << ++i << endl, cerr << --i << endl;
>> i = 5;
>> cerr << ++i << endl << --i << endl;
>> i = 5;
>> cerr << ++i + --i << endl;
>>
>> Compiled with egcs 2.91.66, this gives 6 5 6 5 11 under Solaris and
>> 6 5 5 4(!) 10 under Linux. I did expect 5 5 5 5 10. Is this
>> behaviour defined exactly anyway ?
>>
>6 5 6 5 11 should be the correct result (at least I think so...).
A look at the language definition would show that the expression
++i + --i
attempts to modify an object more than once between sequence
points. The program therefore has undefined behavior, and any
result at all is possible. Refer to section 1.9 in the C++ standard.
--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 1999/09/17 Raw View
Francis Glassborow wrote:
>
> > cerr << ++i << endl << --i << endl;
>
> You now have two writes to i between sequence points, assuming that the
> << is not a function call and you have undefined behaviour.
Even if << is a function call. The rule says "for all allowable orderings."
The compiler is free to evaluate (++i) and (--i) before calling any
of the operator<< functions.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 1999/09/17 Raw View
"Siemel B. Naran" wrote:
>
> However, I recall a bizarre thread that said that operators for builtin
> types are different in that the side effects may occur at the end of
> the full expression. Hence the above would be the same as
> cerr << i << endl, cerr << i << endl , ++i , --i;
> And so the output may be "5 5".
>
I don't know what's bizarre about it, other than the expression you
wrote yields different results than what the standard requires.
Perhaps what you mant was this may happen:
int t1, t2; // T are compiler issued temporaries.
t1 = i + 1
t2 = i - 1
cerr << t1 << endl
cerr << t2 << endl
i = t1
i = t2
Of course, this is still incorrect with the standard. The whole
point of sequence points (which , is one) is to guarantee at that
point that the obervable parts (Notably the value of the variable
i) have their defined variables at that part.
Without the interior sequence points, you are right, you do not know when
the side effect occurs, which could be anytime up until the next
sequence point (end of the full expression).
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: sbnaran@uiuc.edu (Siemel B. Naran)
Date: 1999/09/17 Raw View
On 16 Sep 1999 22:07:43 GMT, Hyman Rosen <hymie@prolifics.com> wrote:
>sbnaran@uiuc.edu (Siemel B. Naran) writes:
>> But why does G++ under Linux give 10?
>
>It's undefined behavior, so asking why is silly.
It's not silly. I expect to see either "9" or "11", not "10". It
is reasonable to ask why, especially if you are interested in how
your compiler compiles.
>> There is a special rule about builtin operators, that IMHO should not be.
>
>What is this mysterious rule you're talking about?
>I don't think any such rule exists.
See the post by Steve Clamage. He gives an example like this
Int x(1);
x = ++x + 1;
std::cout << x;
If 'Int' is a user-defined class, then the above is equivalent to
operator=(x,operator+(operator++(x),1));
which is well defined. The result is "3".
If 'x' is a builtin type, then the above is equal to either of
++x , x=x+1 ;
x=x+1 , ++x ;
So the result is "2" or "3".
It is mysterious/bizarre that the result of builtin operators and
user defined operators are different.
On the other hand, I prefer not to have to deal with code like
"x=++x+1" anyway as it is somewhat hard for humans to parse.
--
--------------
siemel b naran
--------------
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: dvandeun@vub.ac.be (Dirk van Deun)
Date: 1999/09/16 Raw View
int i = 5;
cerr << ++i << endl, cerr << --i << endl;
i = 5;
cerr << ++i << endl << --i << endl;
i = 5;
cerr << ++i + --i << endl;
Compiled with egcs 2.91.66, this gives 6 5 6 5 11 under Solaris and
6 5 5 4(!) 10 under Linux. I did expect 5 5 5 5 10. Is this
behaviour defined exactly anyway ?
(I saw a program segfault under one OS while it worked fine under
the other because of pre-increment combinations on iterators...)
Dirk van Deun Ceterum censeo Redmond delendum
--
Currently at: dirk@igwe.vub.ac.be http://student.vub.ac.be/~dvandeun
Permanent mail forwarder: dvandeun@poboxes.com
--
Knight of the Order of the Command Line --- http://knights.rave.org
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Ken Hagan" <K.Hagan@thermoteknix.co.uk>
Date: 1999/09/16 Raw View
I think the first statement has to result in "6 5". The comma is a
sequence point, so the "++i" has to be fully evaluated (and the
result stored) before beginning the second part.
The second statement is undefined, since "<<" is not an operator
which has a sequence point. (Actually, I don'y think any _overloaded_
operator has a sequence point, but no doubt someone will correct
me if I'm wrong.) In the absence of that sequence point, the compiler
is free to evaluate both "++i" and "--i" in pseudo parallel -- that is,
it can load the starting value of i into two registers, decrement one
and increment the other, and write them back in either order. You
might find it interesting to insert "cerr << i << endl;" after each of
the three examples.
The third line suffers from the same ambiguity. I think the complete
range of possibilities is
--i to get 4, store, ++i to get 5, store == 9 (and i is 5 afterwards)
--i to get 4, ++i to get 6, store both == 10 (and i is 4 or 6)
++i to get 6, store, --i to get 5, store == 11 (and i is 5)
++i to get 6, --i to get 4, store both == 10 (and i is 4 or 6)
A good compiler will issue a warning for the second and third of your
examples. A bad set of system headers will disable that warning to
cover up your vendor's own poor coding standards.
Dirk van Deun wrote in message <7rp3ik$3mk$1@mach.vub.ac.be>...
> int i = 5;
> cerr << ++i << endl, cerr << --i << endl;
> i = 5;
> cerr << ++i << endl << --i << endl;
> i = 5;
> cerr << ++i + --i << endl;
>
>Compiled with egcs 2.91.66, this gives 6 5 6 5 11 under Solaris and
>6 5 5 4(!) 10 under Linux. I did expect 5 5 5 5 10. Is this
>behaviour defined exactly anyway ?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/09/16 Raw View
Dirk van Deun wrote:
>
> int i = 5;
> cerr << ++i << endl, cerr << --i << endl;
This first one is OK: "," defines a sequence point, that is,
the expression left of it must be completely evaluated before
the second one. Since you used prefix operator++/--, the
increment/decrement is done before using the value, so the left
expression prints "6", and the right one prints "5".
> i = 5;
> cerr << ++i << endl << --i << endl;
This one is not OK: There is no sequence point between ++i
and --i, so the behaviour is undefined. The most probable
behaviours I'd expect would be
- print 6 5 (evaluation left to right)
- print 5 4 (evaluation right to left)
> i = 5;
> cerr << ++i + --i << endl;
Same problem here. "+" doesn't introduce a sequence point
as well, so again this is undefined. Most probable outcomes:
- print 11 (left to right)
- print 9 (right to left)
>
> Compiled with egcs 2.91.66, this gives 6 5 6 5 11 under Solaris and
> 6 5 5 4(!) 10 under Linux. I did expect 5 5 5 5 10. Is this
> behaviour defined exactly anyway ?
The behaviour of the first expression is well defined, and it
must output "6 5". The rest is undefined. So gcc is right both
on Solaris and on Linux.
A variable may not be modified twice without a sequence point
in between. Sequence points are inserted
- at the end of each statement
- for built-in operator&&, operator|| and operator,
- just before and after a function call (but _not_ between
evaluation of different arguments, even if they are arguments
to different functions)
- between initializing different variables (that is,
"int a=0, b=++a, c=++a;" is well defined (and makes a=c=2, b=1)
- between constructor initializers (that is,
"class Foo: Bar, Baz { Foo(int i): Bar(i++), Baz(i++) {} };"
is well defined as well - but I might be wrong here)
(Any case I've forgotten?)
[...]
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Robert Kolter <kolter@student.uni-kl.de>
Date: 1999/09/16 Raw View
Dirk van Deun schrieb:
> int i = 5;
> cerr << ++i << endl, cerr << --i << endl;
> i = 5;
> cerr << ++i << endl << --i << endl;
> i = 5;
> cerr << ++i + --i << endl;
>
> Compiled with egcs 2.91.66, this gives 6 5 6 5 11 under Solaris and
> 6 5 5 4(!) 10 under Linux. I did expect 5 5 5 5 10. Is this
> behaviour defined exactly anyway ?
>
6 5 6 5 11 should be the correct result (at least I think so...). I have
absolute no idea, why you get the second result (the one under Linux...).
Perhaps a bug of your compiler...
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Gabriel Dos_Reis <gdosreis@korrigan.inria.fr>
Date: 1999/09/16 Raw View
dvandeun@vub.ac.be (Dirk van Deun) writes:
| int i = 5;
| cerr << ++i << endl, cerr << --i << endl;
| i = 5;
| cerr << ++i << endl << --i << endl;
| i = 5;
| cerr << ++i + --i << endl;
^^^^^^^^^
You're invoking undefined behaviour.
--
Gabriel Dos Reis, dosreis@cmla.ens-cachan.fr
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]