What is the outcome of running the following code:
int c=0;
cout<<c++<<c;
The answer says undefined. But in this case, isn't this statement
translated into:
cout.operator<<(c++).operator<<(c);
There should be a sequnce point before calling a funcion after
evaluation of the arguments. So shouldn't the incremented value of c be
stored before the call to first <<. If so it should be available for
the second <<, and the result would be 01.
Please help me with this confusion.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Well, the operators . are part of the expression, aren't they? If you
think so, then you have to accept that both sides of that operator
(the object expression and the function call expression) can be
evaluated in any order before the operator . is evaluated. That means
that
(cout.operator<<(c++))
can be evaluated after
(c)
in preparation to the second call. There are sequence points, yes.
The calls to the functions are sequenced, there is no doubt. But the
arguments of those functions can be evaluated in any order, and it is
completely up to the compiler. Which means that both 'c' and 'c++'
can be evaluated in any order before the first sequence point is hit.
Which means that the value of 'c' object is changed and accessed in
the same expression between sequence points. Behaviour is undefined.
V
--
Please remove capital As from my address when replying by mail
> Hello,
> I was solving a C++ quiz that has the following question:
>
>
> What is the outcome of running the following code:
>
> int c=0;
> cout<<c++<<c;
>
> The answer says undefined. But in this case, isn't this statement
> translated into:
>
> cout.operator<<(c++).operator<<(c);
The two calls to operator<< must indeed be made in this order. That
is because to make the second operator<< call, it must have two
things, namely the stream object to call it on and the parameter to
pass. But there is no requirement for it to evaluate these two things
in any given order.
Let's rewrite this as, just to make the explanation simpler:
int a = 10, b = 20;
cout << a << b;
Now we can call the two function calls 'A' and 'B' respectively. To
make the second function call, 'B', two expressions must be evaluated,
namely the reference returned by call 'A', and the value of the int
'b'. But since the ordering of evaluation of arguments to functions
is completely unspecified, there is nothing from preventing the
compiler from doing this:
evaluate 'b' (lvalue to rvalue conversion), save value in a register
evaluate 'A' (call it and get the reference it returns), which in
turn involves the following two evaluations, which can also be done in
any order:
evaluate 'a' (lvalue to rvalue conversion)
evaluate 'cout'
call cout.operator<<a
> There should be a sequnce point before calling a funcion after
> evaluation of the arguments. So shouldn't the incremented value of c be
> stored before the call to first <<. If so it should be available for
> the second <<, and the result would be 01.
There is indeed a sequence point before calling a function after
evaluation of the arguments, but there is nothing in the C++ standard
that forbids the compiler from evaluating 'b' before it evaluates 'a'.
These two evaluations are at the same level.
> Please help me with this confusion.
--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
> I was solving a C++ quiz that has the following question:
> What is the outcome of running the following code:
> int c=0;
> cout<<c++<<c;
> The answer says undefined.
It's not just the output which is undefined, it's the behavior
in general.
> But in this case, isn't this statement translated into:
> cout.operator<<(c++).operator<<(c);
> There should be a sequnce point before calling a funcion after
> evaluation of the arguments.
There's a sequence point before calling a function and when
returning from one. But the standard explicitly says that the
order of evaluation is unspecified. There is one implicit
constraint on the ordering: that the first operator<< be called
before the second, since its return value is an operand of the
second. But that is all. A compiler is free to evaluate all of
the other operands in any order it wishes, before calling the
first operator<<. Which means that there is no sequence point
between reading c as operand of the second <<, and evaluating
c++ as operand for the first.
> So shouldn't the incremented value of c be stored before the
> call to first <<.
Yes. But the compiler can also evaluate the expression "c" for
the second operand of the second << before calling the first <<;
in fact, this is pretty much standard practice on machines where
the stack grows downward (IA-32, Sparc...).
> If so it should be available for the second <<, and the result
> would be 01.
> Please help me with this confusion.
The problem is that sequence points only introduce a partial
ordering. Here, they impose the complete evaluation of c++
(including all side effects) before the call to the first <<,
but they impose no order with regards to the rest of the
expression, e.g. the second argument of the second <<.
--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Many people will post the correct answer,
but the only way to help with this confusion
is to finally change the C++ standard to give
expressions a defined order of evaluation,
as Java has done.
JB
Do we have to?
We can always specify an exact ordering of evaluation when it's needed,
and I don't see why it's sometimes argued that the language should
specify an exact ordering of evaluation, even though it may limit
compilers' flexibility in optimization.
--
Seungbeom Kim
True as far as it goes, but c++ and c can both be evaluated before
either function call. That is where the undefined behaviour creeps in.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
Actually that does not solve the problem, you would have to go a step
further and require a defined order of side-effects.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
I am having difficulty with untangling what you mean. The increment must
have been applied before the next sequence point. The problem is that
there is no required sequence point between the evaluation of the c++
and the evaluation of the c so c is read twice and written once without
a required intervening sequence point (even though there will be one for
some sequences of evaluation.
The undefined behaviour is because the second (lexically) read of c
could happen whilst c is being written to and so is in some intermediate
state between 0 and 1.
--
Francis Glassborow ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
> Do we have to?
> We can always specify an exact ordering of evaluation when
> it's needed, and I don't see why it's sometimes argued that
> the language should specify an exact ordering of evaluation,
> even though it may limit compilers' flexibility in
> optimization.
Reproducibility.
If you don't care if your code will ever have to run with
different compiler options, or a later version of the compiler,
it makes no difference.
If your organization is so good that you can be 100% certain
that the rules are never violated, it also makes no difference.
I think, however, that most organizations fall between these two
extremes. And to date, there's been no real evidence of where
any loss of optimization would actually occur, enough to affect
real programs. (It could make the same level of optimization
harder in some cases, but on the whole, all of the real loss of
optimization cases I've seen involve non-inlined function calls.
And the difference is always very, very small compared to the
execution time of a function too large to be inlined.)
--
James Kanze kanze...@neuf.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
> Actually that does not solve the problem, you would have to go a step
> further and require a defined order of side-effects.
It's more or less implicit. The full ordering he is talking
about comes to about the same thing as inserting a sequence
point between every operator.
--
James Kanze kanze...@neuf.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]