#include<iostream>
using namespace std;
int main()
{
int x = 0;
x = x++;
cout << x << endl;
}
The output was:
1
Now, I KNOW for a FACT that MSVC is not 100% conformant to the C++
standard, so I tend to trust my intuition and logic over the results
MSVC gives me (for example, MSVC gives me a warning about main not
returning a value =) But in this case I'm really not sure.
It seems to me that the x++ occurrs first, as the postfix increment
operator is higher in precedence than the assignment operator. Thus
the value at memory location is 1, but the result of the expression
x++ is 0 (the previous value of x). Then this value (0) should be
assigned to the memory location identified by x, overwriting the
effect of the increment. So, I should be getting 0. Is my
logic/understanding flawed?
I also tried writing:
int x = 0;
cout << x++ << endl << x << end;
and I got
0
1
Then I wrote a little class
class Number
{
int n;
public:
Number(int num=0) : n(num) { }
Number& operator++() { ++n; return *this; }
Number operator++(int) { Number prev = *this; ++n; return
prev; }
friend ostream& operator<<(ostream& os, const Number& num);
};
ostream& operator<<(ostream& os, const Number& num)
{ return os << num.n; }
When I replaced Number for int in my first program, ie:
int main()
{
Number n = 0;
n = n++;
cout << n << endl;
}
I got
0
So that worked like I thought it would. Now, naturally, I DEFINED the
postfix increment operator to work like I thought it should, but isn't
this the *correct* way to write it?
I can't back this up with a solid argument (mostly because I have a
very weak understanding of sequence points), but I feel that this is
related to the (a = b) = c problem that has been discussed recently,
bucause both statements involve two modifications of a single memory
location without (I think) a sequence point..
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]
Unfortunately, your logic is flawed. You have introduced undefined
(or unspecified) behaviour.
The code above introduces undefined/unspecified behaviour because x is
modified twice between two sequence points (in the code
above "sequence points" are indicated by semi-colons).
>
> I also tried writing:
> int x = 0;
> cout << x++ << endl << x << end;
>
> and I got
> 0
> 1
With this one, the results are also undefined. You
could equally well get 0 both times. The reason is that
the expression x++ is not guaranteed to be evaluated
before x.
The cout << line could have the effect of
cout << x++;
cout << endl << x << end;
(which gives the results you're seeing) or as
cout << x << endl << x << end;
x++;
(which would give 0 both times).
Formally, the results are undefined, so any other
behaviour is possible too. The reason is that, again
sequence points are indicated by semi-colons.
To (hopefully) help you understand the role of sequence points,
the following statement does not include sequence
points between the calls of x() and y().
cout << x() << ' ' << y() << endl;
The order of calling x() and y() is not specified by
the languagage, so the above *could* be expanded
as ...
int t_y = y(); // assume x() and y() return int
int t_x = x();
cout << t_x << ' ' << t_y << endl;
or as ....
int t_x = x(); // note change of order
int t_y = y();
cout << t_x << ' ' << t_y << endl;
It is fairly trivial to detect the order in which x()
and y() are called, but the results will vary between
compilers.
[Snip]
> int main() {
> int x = 0;
> x = x++;
> cout << x << endl;
> }
> The output was: 1
> Now, I KNOW for a FACT that MSVC is not 100% conformant to the C++
> standard, so I tend to trust my intuition and logic over the results
> MSVC gives me (for example, MSVC gives me a warning about main not
> returning a value =) But in this case I'm really not sure.
> It seems to me that the x++ occurrs first, as the postfix increment
> operator is higher in precedence than the assignment operator. Thus
> the value at memory location is 1, but the result of the expression
> x++ is 0 (the previous value of x). Then this value (0) should be
> assigned to the memory location identified by x, overwriting the
> effect of the increment. So, I should be getting 0. Is my
> logic/understanding flawed?
Yes. While you're right wrt. the precedence order, that just means you
cant parse the line as (x=x)++;. However, precedence order doesn't say
anything about the order of execution. In general C++ says very little
about the order in which things happen between "sequence points". The
relevant sequence points here are the start of main, and end of the
statement x=x++; (IIRC, int x=0; isn't a statement but a definition)
That means the compiler can decide to do the store of x=0 first, or
do the store of x++ first. Both are correct. Apparently, MSVC++ in this
case decided to store the 0 first, and then overwrite it with 1. It's
also possible that MSVC++ decided to store 1 first, and then discarded
the second assignment since no sequence point was seen between the
assignments.
> I also tried writing:
> int x = 0;
> cout << x++ << endl << x << end;
> and I got
> 0
> 1
Which is a related problem. C++ doesn't specify the order of evaluation
of function arguments. In this case, it seems x++ was evaluated first, and
then x was read after x++ was stored. This is allowed. The simple
example is
void f(int, int);
int g();
int h();
f(g(), h());
You don't know which function will be called first, only that f() will be
called last.
> Then I wrote a little class
> class Number
> {
> int n;
>
> public:
> Number(int num=0) : n(num) { }
> Number& operator++() { ++n; return *this; }
> Number operator++(int) { Number prev = *this; ++n; return
> prev; }
> friend ostream& operator<<(ostream& os, const Number& num);
> };
> ostream& operator<<(ostream& os, const Number& num)
> { return os << num.n; }
> When I replaced Number for int in my first program,
> I got 0
> So that worked like I thought it would. Now, naturally, I DEFINED the
> postfix increment operator to work like I thought it should, but isn't
> this the *correct* way to write it?
This is besides the point. You introduced functions. A function call
introduces one sequence point, after evaluation of all arguments
and before execution of the function body.
As you noticed, there isn't one in the middle of evaluation.
> I can't back this up with a solid argument (mostly because I have a
> very weak understanding of sequence points), but I feel that this is
> related to the (a = b) = c problem that has been discussed recently,
> bucause both statements involve two modifications of a single memory
> location without (I think) a sequence point..
Precisely. In your first example, you're modifying x twice between
sequence points. With the class Number, you introduce a sequence
point between the modifications, and suddenly everything works as
defined.
Michiel Salters
> OK, I tried this code on MSVC6:
>
> #include<iostream>
> using namespace std;
>
> int main()
> {
> int x = 0;
> x = x++;
> cout << x << endl;
> }
>
> The output was:
> 1
It could have formatted your hard drive.
> I can't back this up with a solid argument (mostly because I have a
> very weak understanding of sequence points), but I feel that this is
> related to the (a = b) = c problem that has been discussed recently,
> bucause both statements involve two modifications of a single memory
> location without (I think) a sequence point..
You've got it. Your class did what you expect because both = and ++
are functions which introduce sequence points.
For your builtin example consider
r1 = x
r2 = r1
r2 += 1
sequence point, so do the stores in some order
x = r1 // covers the assignment
x = r2 // now that we are done, lets store the new value in x
Since stores can be done at any time, it could also be
r1 = x
x = r1 // silly but it covers the assignment and y = x ++ works
r1 += 1
x = r1 // now store the new value
My favorite is
x = 3;
cout << (++ x + ++ x) + ++ x << endl;
x = 3;
cout << ++ x + (++ x + ++ x) << endl;
It is not unusual to find that addition is not associative when you
introduce undefined behavior.
John
Josh Sebastian <cur...@earthlink.net> wrote in
comp.lang.c++.moderated:
>OK, I tried this code on MSVC6:
> x = x++;
>
>Now, I KNOW for a FACT that MSVC is not 100% conformant to the C++
>standard, [...]
>It seems to me that the x++ occurrs first, as the postfix increment
>operator is higher in precedence than the assignment operator.
That's not what "precedence" means. Precedence is simply implicit
parentheses to govern how expressions are interpreted, so the
expression
x = x++
means
x = (x++)
and not
(x = x)++.
BUT the precedence does not guarantee that all operations of a
higher precedence will be done before operations of a lower
precedence. All you can count on by way or order of operations is
that everything up to a "sequence point" is done before anything
after that sequence point.
There's a list of sequence points somewhere, but the most
recognizable are
the ; at the end of a statement
the short-circuit operators || and &&
So when you write
x = x++;
you know that x will be incremented, and you know that some value of
x will be assigned to x, but you don't know the order in which those
will happen. Similar ambiguities exist with expressions like
a[x++] = x
and
f(x++, x, x++);
Since << is a function call with ostreams, you have many possible
outputs for
std::cout << x << ' ' << x++ << ' ' << x << ' ' << x++;
Actually, it's even worse than just not knowing what numbers will be
stored or output: the above actually lead to undefined behavior
which means that *anything* could happen.
I don't know where, or if, this problem is explained in the C++ FAQ
(URL in my sig); but it is explained in Steve Summit's excellent C
FAQ, <http://www.eskimo.com/~scs/C-faq/versions.html>. Look
specifically at questions 3.1 through 3.9.
--
Stan Brown, Oak Road Systems, Cleveland, Ohio, USA
http://oakroadsystems.com
C++ FAQ Lite: http://www.parashift.com/c++-faq-lite/
the C++ standard: http://webstore.ansi.org/
illegal identifiers: http://oakroadsystems.com/tech/cppredef.htm
more FAQs: http://oakroadsystems.com/tech/faqget.htm
Toward the end of 1.9 of the standard. Since sequence points seemed
rather arcane to me until I got a copy of the standard, let me try to
spell them out for the benefit of those wondering what they are.
Proofreading welcomed, especially on #3. :)
1. The end of each full expression. (1.9/16)
These are usually marked by a ; but can occasionally be marked by
other things, for example, a ) in a class initialiser.
Example:
int main()
{
int x = 5;
std::cout << x << std::endl; // guaranteed to print 5
}
2. At point of function call. (1.9/17)
This relates to evaluation of the function's arguments only.
Example (expanding previous):
int foo(int& x) { return x;}
int main()
{
int x = 5;
std::cout << foo(x=6) << std::endl; // guaranteed to print 6
}
3. At point of return from function call. (1.9/17)
After copying of return value and prior to other expressions
outside of function. I'm a little fuzzy on the meaning of this one.
As I understand it:
Example (expanding previous):
int foo(int& x) { return x -= 2;}
int main()
{
int x = 5;
std::cout << x + foo(x=6) + x << std::endl; // guaranteed to print 12
// But note:
std::cout << foo(x) + foo(x) << std::endl; // undefined behaviour
}
4. (1.9/18) After the first expression ('a' here) in:
a || b
a && b
a , b
a ? b : c
These are harder to show by example, because precedence rules make
you think that the parentheses are doing the work. But here is an
example:
int x =0;
(x = 7) && (x = 5);
std::cout << x << std::endl; // guaranteed to print 5
(x = 7) & (x = 5); // undefined behaviour
Note the ternary operator pitfall: there is only one sequence
point, at the ? (aside from the other pitfall which is that the
second and third expressions are both always evaluated):
int y = 0;
int x = (y = 5) > 0 ? y++ : y; // y guaranteed to be 6 afterwards
int x = (y = 5) > 0 ? y++ : y++; // undefined, two modifications
// to y without sequence point
int x = y > 0 ? y++ : y++; // also undefined
--
- Bruce
I don't think so. Do you have a reference?
When I compile and run this:
#include <iostream>
int main()
{
{
int y = 5;
int x = y < 0 ? y++ : y;
cout << x << ' ' << y << '\n';
}
{
int y = 5;
int x = y > 0 ? y : y++;
cout << x << ' ' << y << '\n';
}
}
with gcc version 2.95.2 19991024 (release)
I get this:
5 5
5 5
which indicates that the second expression is NOT evaluated
when the condition is true, and
that the third expression is NOT evaluated
when the condition is false.
Dennis Yelle
--
I am a computer programmer and I am looking for a job.
There is a link to my resume here: http://table.jps.net/~vert
No, it's not. The above line has perfectly defined behavior,
since the << involves a function call, which introduces a
sequence point.
> You
> could equally well get 0 both times. The reason is that
> the expression x++ is not guaranteed to be evaluated
> before x.
It is. The above line is parsed as this (or something
equivalent):
(((cout.operator<<
(x++)).operator<<(endl)).operator<<(x)).operator<<(endl);
Before actually calling the first function, the side effect of
x++ must have taken place, since calling a function introduces
a sequence point.
Carlos
--
> Bruce DeVisser wrote:
>
> > Note the ternary operator pitfall: there is only one sequence
> > point, at the ? (aside from the other pitfall which is that the
> > second and third expressions are both always evaluated):
>
> I don't think so. Do you have a reference?
> When I compile and run this:
...
Running a test program isn't a very good indication of what the Standard
has to say (the compiler you're using could be nonconforming, after all)
...
> which indicates that the second expression is NOT evaluated
> when the condition is true, and
> that the third expression is NOT evaluated
> when the condition is false.
But you're correct. There is a sequence point after the conditional
expression is evaluated, but before the resultant expression is
evaluated, and exactly one of the second and third expressions are
evaluated. ISO/ANSI C++, 5.16/1.
--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, US / 37 20 N 121 53 W / ICQ16063900 / &tSftDotIotE
/ \ You are free and that is why you are lost.
\__/ Franz Kafka
Crank Dot Net / http://www.crank.net/
Cranks, crackpots, kooks, & loons on the Net.
First, I firmly believe that the built-in types should behave in
fundamentally the same manner as a properly defined arithmetic class.
I always wondered why C++ didn't define "functions" to represent
operations on primitive data types (like Ada does). This just
entrenches my belief. So why didn't they?
It seems to me that there wouldn't be a problem if a sequence point
were introduced between the left and right sides of the assignment
operator. In fact, it seems to me that there should be a sequnce point
between ALL binary operators. This could, in lieu of making all
primitive operators functions, make a primitive data type and an
arithmetic class behave identically.
______________
"Yields falsehood when preceded by its quotation" yields falsehood when
preceded by its quotation!
Josh Sebastian
<cur...@earthlink.net>
I don't know if your comments above will be taken seriously or not.
It is one of those deep and interesting questions that can be
asked by a novice, so some people just do not know how to respond.
One reason is that most of the built-in types were inherited from C and,
in the beginning, it was considered important that they behave
exactly the same in C and C++. Some people think that we cannot
do what you suggest without either breaking compatibility with C
or making programs run much slower than they do today or both.
I, myself, am not convinced. It is very difficult to prove something
is impossible. On the other hand, I am too lazy to try to prove
that it is not impossible.
Dennis Yelle
--
I am a computer programmer and I am looking for a job.
There is a link to my resume here: http://table.jps.net/~vert
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
> Note the ternary operator pitfall: there is only one sequence
> point, at the ? (aside from the other pitfall which is that the
> second and third expressions are both always evaluated):
> int y = 0;
> int x = (y = 5) > 0 ? y++ : y; // y guaranteed to be 6 afterwards
> int x = (y = 5) > 0 ? y++ : y++; // undefined, two modifications
> // to y without sequence point
> int x = y > 0 ? y++ : y++; // also undefined
>
No no no. Only one of the alternatives is evaluated.
"There is only one sequence point, at the ?" forbids
x = 1 + (y == 0) ? (x = 5) : z;
but allows:
x = (x++ == 0) ? y : z;
The store x in x++ must be completed before the sequence point
associated with ?.
I would think that x = b ? y++ : y--; is well defined: x and y will each
be updated once for any execution of the statement.
> I don't think so. Do you have a reference?
Yes, I have a reference, and you are correct. Sheesh, a basic
concepts, you'd think I haven't read anything. Well, at least you know
one thing about my coding style: I don't put side-effect expressions
into the second and third expressions of a conditional; if I did, I'd
know better.
5.16/1 says:
Conditional expressions group right-to-left. The first expression
is implicitly converted to bool (clause 4). It is evaluated and if
it is true, the result of the conditional expression is the value of
the second expres- sion, otherwise that of the third expression. All
side effects of the first expression except for destruction of
temporaries (12.2) happen before the second or third expression is
evaluated. Only one of the second and third expressions is
evaluated.
Thanks for the correction, and my apologies for the rotten example.
--
- Bruce
Well actually it sort of does, but it says nothing about the order in
which sub-expressions and operands are evaluated except that they must
be evaluated by the time the operator is evaluated.
Francis Glassborow 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
I can see how it may compromise combatablity with C but not how it
would sacrifice speed. After all, there are already several operators
that have function-like syntax. Namely, the new-style casts and the
sizeof operator. And sizeof was even part of C!
It would raise many difficulties though. Oh well. I can live with it.
______________
"Yields falsehood when preceded by its quotation" yields falsehood when
preceded by its quotation!
Josh Sebastian
<cur...@earthlink.net>
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
Pitfall? No, it is your misunderstanding. The compiler MUST NOT evaluate
the both the second and third expressions but only the appropriate one.
Francis Glassborow 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
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
But adding sequence points basically only changes into specified
behaviour what was previously unspecified. Specifying something
in C++ where C was allowed to do anything would not be a concern
for backwards compatibility of user code.
>Some people think that we cannot
>do what you suggest without either breaking compatibility with C
>or making programs run much slower than they do today or both.
Sequence points are needed for the result of a program to be defined.
However, adding too many sequence points does impair the compiler's
ability to produce optimized code.
For example, reordering assembly instructions can have a major
performance impact on modern processors, as well as the caching
of variables that have to be read from memory.
But this does not really matter.
Why would you want to have more sequence points anyway ?
What would it bring other than new opportunities for
creating obfuscated code ?
I would never write code like x = ++x or y = ++x + (z=++x)
even if their result was well defined.
Take a well specified thing like operator precedence: most
coding style guidelines will require the use of parentheses
rather than to rely on implicit order. Because if you read code that
says a = b == c << d & e , even you know exactly what it does, you
can't usually be sure that the guy who wrote it knew it well too.
The behavior is specified, but what is the benefit ?
When you face undefined behaviour with the current sequence points,
you probably should be breaking up your code statements anyway.
Look at the flexibility we have with type expressions (e.g.
typedef struct tag (*)(char*)(*f[5])(double (*)[3]); ),
Is there any real benefit in being allowed to write such things ?
>I, myself, am not convinced. It is very difficult to prove something
>is impossible. On the other hand, I am too lazy to try to prove
>that it is not impossible.
My own perspective would be that I do not care about what
is possible, but what is practical.
True, there are discrepancies between the behaviour of built-in
and user-defined operators, but they are easy to keep ouside of
the realm of useful C++ constructs - in my humble experience.
Any counter-examples ?
Regards,
Ivan
--
"Si on avait pu naitre avant l'Homme !" - Cioran
----------------------------------------------------
Ivan Vecerina, Dr. med. , Senior Software Engineer
http://www.surgnav.com - http://www.cedara.com
Sent via Deja.com http://www.deja.com/
Before you buy.
> Robert O'Dowd wrote:
[ OP' name got lost somewhere ]
> > > I also tried writing:
> > > int x = 0;
> > > cout << x++ << x << end;
> > > and I got
> > > 0 1
> > With this one, the results are also undefined.
> No, it's not. The above line has perfectly defined behavior,
> since the << involves a function call, which introduces a
> sequence point.
[ SNIP ]
> The above line is parsed as this (or something
> equivalent):
> (((cout.operator<< (x++)).operator<<(x)).operator<<(endl);
> Before actually calling the first function, the side effect of
> x++ must have taken place, since calling a function introduces
> a sequence point.
True. But at the moment the first function is called x might already
have been evaluated. The reason is that for member functions, there
is no sequence point between evaluating the lhs and the arguments,
i.e. if we have GetObjRef().Member(GetArg()) there is no sequence
point between GetObjRef() and GetArg(), and they may happen in any
order.
By this rule, the first part of your expression (which seems correct
to me), (cout.operator<< (x++) may be evaluated before or after
evaluating x in .operator<<(x). Thus x may be 0 or 1.
Ergo, this leads to unspecified behavior. I don't think the compiler
is allowed to do anything than choose any order it likes, possibly
even a random order. But that's the only degree of freedom it has.
It's neither defined nor undefined.
Regards,
Michiel Salters
> Toward the end of 1.9 of the standard. Since sequence points seemed
> rather arcane to me until I got a copy of the standard, let me try to
> spell them out for the benefit of those wondering what they are.
> Proofreading welcomed, especially on #3. :)
> 3. At point of return from function call. (1.9/17)
> After copying of return value and prior to other expressions
> outside of function. I'm a little fuzzy on the meaning of this one.
Me too. An example would sure help. I don't have one either.
> As I understand it:
> Example (expanding previous):
> int foo(int& x) { return x -= 2;}
There is a sequence point at the end of the expression x -= 2. The
value of this expression is copied to a temporary int and then there
is another sequence point? What if there were local objects with
dtors? Could they be run in parallel with calling code or are they
outside of the function? Would it make a difference? I think they
are functions and can not be run in parallel; however, do they need
to be run prior to calling code?
> int main()
> {
> int x = 5;
> std::cout << x + foo(x=6) + x << std::endl; // guaranteed to
> // print 12
Nope. The only sequence point of interest is the function call. The
only requirement is that its parameter be evaluated prior to the call.
The two other evaluations of x can be performed in any order before or
after the call.
x (5), x (5), x = 6, foo (4) 14
x (5), x = 6, x (6), foo (4) 15
x (5), x = 6, foo (4), x (4) 13
x = 6, x (6), x (6), foo (4) 16
x = 6, x (6), foo (4), x (4) 14
x = 6, foo (4), x (4), x (4) 12
Note that this is unspecified behavior because of the order of
evaluation of the operands of +. Since some of those allowed sequences
use the old value of x and modify x without a sequence point, we get
undefined behavior. The sequence points do not prohibit the
implementation from generating code which uses the old value of x, they
prohibit the user from writting code which allows it and expecting
anything reasonable.
> // But note:
> std::cout << foo(x) + foo(x) << std::endl; // undefined behaviour
> }
Here we have sequence points and pass by reference. It makes no
difference when we evaluate the operand of foo because it is always
the lvalue x. The lvalue to rvalue conversion takes place within
foo.
foo1 (3), foo2 (1) 4
foo2 (3), foo1 (1) 4
If the operator were - rather than +, the unspecified result would
be either 2 or -2, but there is no undefined behavior.
Replacing foo(x=6) with foo(x) in the first example gives
x (5), x (5), foo (3) 13
x (5), foo (3), x (3) 11
foo (3), x (3), x (3) 9
with no undefined behavior.
Is that sequence point at function return after copying the result to
the return area or after copying it from the return area? In this
example, the return area is likely a register and there is no copy
from it.
Can anyone give an example where a program would have well defined
behavior with the return sequence point and unspecified or undefined
behavior without it?
John
> There is a sequence point at the end of the expression x -= 2. The
> value of this expression is copied to a temporary int and then there
> is another sequence point? What if there were local objects with
> dtors? Could they be run in parallel with calling code or are they
> outside of the function? Would it make a difference? I think they
> are functions and can not be run in parallel; however, do they need
> to be run prior to calling code?
Hmm. Are you referring to something like this?:
using namespace std;
struct Foo
{
Foo(int& x) : mX(x) {}
~Foo() { mX = 3; }
int& mX;
};
int Bar(int& x)
{
Foo foo(x);
return x = 4;
}
int main()
{
int x = 5;
cout << Bar(x) << endl;
cout << x << endl;
cout << x = Bar(x) << endl; // hmmm
}
There is a sequence point at the end of the return statement; there is
a sequence point prior to the evaluation of expressions outside
Bar(x); therefore this is well formed (I hope... not that I would ever
want to use it), and the output should be
4
3
4
>> int main()
>> {
>> int x = 5;
>> std::cout << x + foo(x=6) + x << std::endl; // guaranteed to
>> // print 12
> Nope. The only sequence point of interest is the function call.
> The only requirement is that its parameter be evaluated prior to the
> call. The two other evaluations of x can be performed in any order
> before or after the call.
Okay, I can now see that you are right. I was misunderstanding the
standard at this point.
> Is that sequence point at function return after copying the result to
> the return area or after copying it from the return area? In this
> example, the return area is likely a register and there is no copy
> from it.
I assume it is as if the return statement did the following:
1. Evaluate the return expression, as indicated by the sequence point
at the end of the return statement. Since temporaries (within the
return statement) are destroyed at the end of a statement, and
presumably this includes the return value (big presumption), copy the
value to the 'holding area' before the sequence point.
2. Destroy all auto objects used by the function, using the
end-of-function sequence point.
3. Resume evaluation of calling expression, using the 'holding area'
as a temporary that replaces the function call.
But I may be barking up the wrong tree entirely. Footnote 11, from
1.9/17, seems to say that really this is not an 'extra' sequence
point, but is mentioned to deal with anomalous situations such as
function exit via throw... which is perhaps your point.
> Can anyone give an example where a program would have well defined
> behavior with the return sequence point and unspecified or undefined
> behavior without it?
Check the last line of main() up above. But for anything useful, there
are functions involved, and the sequence points clear up
automatically.
It seems the closer I look at the standard, the less clear it all
becomes.:P
--
- Bruce