Topic: vc 6.0's bug?????


Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 3 May 2006 16:10:05 GMT
Raw View
In article <1146664330.418032.74140@u72g2000cwu.googlegroups.com>,
johnchx2@yahoo.com writes
>Not exactly.  The evaluation sequence above is not equivalent to
>
>  a = b = 2;
>
>because r is not equivalent to (b = 2) -- in particular, if converted
>to an rvalue, it isn't guaranteed to yield the new value of b.  In
>other words, (b=2) is an lvalue, but it's not quite the lvalue you
>might think it is.

I hope you are mistaken because otherwise there is very little purpose
in the change from C.  I believe the following code is intended to be
correct:

int & foo(int & r){
     return r = 2;
}

If it isn't then it would seem that there is a lot of broken code around
that just happens to work.




--
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

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: johnchx2@yahoo.com
Date: 3 May 2006 17:10:01 GMT
Raw View
Francis Glassborow wrote:
> johnchx2@yahoo.com writes
> >Not exactly.  The evaluation sequence above is not equivalent to
> >
> >  a = b = 2;
> >
> >because r is not equivalent to (b = 2) -- in particular, if converted
> >to an rvalue, it isn't guaranteed to yield the new value of b.  In
> >other words, (b=2) is an lvalue, but it's not quite the lvalue you
> >might think it is.
>
> I hope you are mistaken because otherwise there is very little purpose
> in the change from C.  I believe the following code is intended to be
> correct:
>
> int & foo(int & r){
>      return r = 2;
> }
>

I don't see any problem with the code above.

I'm probably sewing unnecessary confusion when I say "not quite the
lvalue you might think it is."  I do *not* mean that the lvalue
designates a different object (e.g. a temporary).

All that I am suggesting is that the lvalue (r = 2) has a property not
shared by any other lvalue designating the same object: it is
guaranteed to evaluate to the new value in an rvalue context even
without an intervening sequence point.

The function above leads to the expected behavior because there's a
sequence point when the function returns, which means that foo() == 2
is guaranteed to be true, and foo() = 3 is well defined since a
sequence point separates the two assignments.

I'm suggesting that the slightly roundabout wording of 5.17/1 is due to
a desire to make a = b = 2 well-defined without actually associating a
sequence point with built-in assignment.

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: James Dennett <jdennett@cox.net>
Date: Sun, 30 Apr 2006 07:29:02 CST
Raw View
Greg Herlihy wrote:
> Momchil Velikov wrote:
>> Alf P. Steinbach wrote:
>>> * fisker0303@126.com:
>>>> In vc 6.0:
>>>>
>>>> #include <iostream>
>>>> using namespace std;
>>>>
>>>> int main()
>>>> {
>>>>         int a = 10;
>>>>         int b = 20;
>>>>         a = (a + b) - (b = a);
>>>>         cout << "a=" << a << ",b=" << b << endl;
>>>>         return 0;
>>>>
>>>> }
>>>>
>>>> Release output : a=20,b=10
>>>> Debug output: a=10,b=10
>>> If it were 'a' being modified, the behavior would not (IMO) be merely
>>> unspecified, but undefined, which is much worse.
>> The behavior is *undefined*, because the expression "a = (a + b) - (b =
>> a);"
>> violates "5. Expressions" [#4]:
>>
>> "...  Furthermore, the prior value shall be accessed only to determine
>>       the value to be stored.  The requirements of this paragraph shall
>>      be met for each allowable ordering of the subexpressions of a full
>>      expression; otherwise the behavior is undefined."
>
> No, the behavior is merely unspecified - not undefined. In other words,
> the variable "a" is certain to have either the value 20 or the value 10
> after the expression is evaluated.
>
> The expression would have to store a value in either "a" or "b" more
> than once for it to have undefined behavior.

It writes to b, and also reads from it for a purpose other
than that to determine the value to be stored.  By the quote
above, the behavior is undefined.  It is *not* necessary for
there to be two writes to an object between sequence points
for there to be undefined behavior (though it is sufficient).

-- James

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: 30 Apr 2006 18:40:05 GMT
Raw View
James Dennett wrote:
> Greg Herlihy wrote:
> > Momchil Velikov wrote:
> >> Alf P. Steinbach wrote:
> >>> * fisker0303@126.com:
> >>>> In vc 6.0:
> >>>>
> >>>> #include <iostream>
> >>>> using namespace std;
> >>>>
> >>>> int main()
> >>>> {
> >>>>         int a = 10;
> >>>>         int b = 20;
> >>>>         a = (a + b) - (b = a);
> >>>>         cout << "a=" << a << ",b=" << b << endl;
> >>>>         return 0;
> >>>>
> >>>> }
> >>>>
> >>>> Release output : a=20,b=10
> >>>> Debug output: a=10,b=10
> >>> If it were 'a' being modified, the behavior would not (IMO) be merely
> >>> unspecified, but undefined, which is much worse.
> >> The behavior is *undefined*, because the expression "a = (a + b) - (b =
> >> a);"
> >> violates "5. Expressions" [#4]:
> >>
> >> "...  Furthermore, the prior value shall be accessed only to determine
> >>       the value to be stored.  The requirements of this paragraph shall
> >>      be met for each allowable ordering of the subexpressions of a full
> >>      expression; otherwise the behavior is undefined."
> >
> > No, the behavior is merely unspecified - not undefined. In other words,
> > the variable "a" is certain to have either the value 20 or the value 10
> > after the expression is evaluated.
> >
> > The expression would have to store a value in either "a" or "b" more
> > than once for it to have undefined behavior.
>
> It writes to b, and also reads from it for a purpose other
> than that to determine the value to be stored.  By the quote
> above, the behavior is undefined.  It is *not* necessary for
> there to be two writes to an object between sequence points
> for there to be undefined behavior (though it is sufficient).

In that case, evaluating this expression:

    a = b = 0;

must also lead to undefined behavior - because it too reads from b "for
a purpose other than that to determine the value to be stored".  And
yet this kind of expression appears so frequently in C++ programs that
it is difficult to imagine that its behavior is, in fact, undefined.

Greg

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: alfps@start.no ("Alf P. Steinbach")
Date: Mon, 1 May 2006 00:14:13 GMT
Raw View
* Greg Herlihy:
> James Dennett wrote:
>> It writes to b, and also reads from it for a purpose other
>> than that to determine the value to be stored.  By the quote
>> above, the behavior is undefined.  It is *not* necessary for
>> there to be two writes to an object between sequence points
>> for there to be undefined behavior (though it is sufficient).
>
> In that case, evaluating this expression:
>
>     a = b = 0;
>
> must also lead to undefined behavior - because it too reads from b "for
> a purpose other than that to determine the value to be stored".  And
> yet this kind of expression appears so frequently in C++ programs that
> it is difficult to imagine that its behavior is, in fact, undefined.

This may not count as a read from b, but rather the result of the
assignment operator.

It may be that my opinion re unspecified versus undefined, expressed
earlier in the thread, needs some revision...

But I think, with the standard that unclear, to the point of confusing
the original authors so that they gave examples contradicting the
normative text, it needs fixing.  E.g., if the intention is that any
expression where different possible evaluation orders of scalar value
operations can yield different results, is undefined behavior, then I
think that should be stated, and not expressed in terms of more
primitive concepts, like a compiled version that must be disassemblied
and analyzed.  But better yet: deterministic, well-defined behavior. ;-)

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: Niklas Matthies <usenet-nospam@nmhq.net>
Date: Sun, 30 Apr 2006 19:56:25 CST
Raw View
On 2006-04-30 18:40, Greg Herlihy wrote:
> James Dennett wrote:
:
>> It writes to b, and also reads from it for a purpose other
>> than that to determine the value to be stored.  By the quote
>> above, the behavior is undefined.  It is *not* necessary for
>> there to be two writes to an object between sequence points
>> for there to be undefined behavior (though it is sufficient).
>
> In that case, evaluating this expression:
>
>     a = b = 0;
>
> must also lead to undefined behavior - because it too reads from b
> "for a purpose other than that to determine the value to be stored".

FWIW, at least in C this expression doesn't read from b.

-- Niklas Matthies

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Victor Bazarov" <v.Abazarov@comAcast.net>
Date: 1 May 2006 01:50:02 GMT
Raw View
Niklas Matthies wrote:
> On 2006-04-30 18:40, Greg Herlihy wrote:
>> James Dennett wrote:
>>
>>> It writes to b, and also reads from it for a purpose other
>>> than that to determine the value to be stored.  By the quote
>>> above, the behavior is undefined.  It is *not* necessary for
>>> there to be two writes to an object between sequence points
>>> for there to be undefined behavior (though it is sufficient).
>>
>> In that case, evaluating this expression:
>>
>>     a = b = 0;
>>
>> must also lead to undefined behavior - because it too reads from b
>> "for a purpose other than that to determine the value to be stored".
>
> FWIW, at least in C this expression doesn't read from b.

What if 'b' is declared 'volatile'?  What if the type of 'b' is not
one of built-ins?

V
--
Please remove capital As from my address when replying by mail


---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: kanze.james@neuf.fr (James Kanze)
Date: Mon, 1 May 2006 14:41:29 GMT
Raw View
Greg Herlihy wrote:

     [...]
 > In that case, evaluating this expression:

 >     a =3D b =3D 0;

 > must also lead to undefined behavior - because it too reads
 > from b "for a purpose other than that to determine the value
 > to be stored".

Where ? I don't see any read from b in that expression.  The
compiler first evaluates b =3D 0 (because that is what is to be
written to a): the result of that expression is the exquivalent
of "static_cast< typeof(b) >( 0 )".  No read from b there.  And
the next sub-expression is the assignment of a.

--=20
James Kanze                                    kanze.james@neuf.fr
Conseils en informatique orient=E9e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France +33 (0)1 30 23 00 34

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: avakar@volny.cz (=?ISO-8859-1?Q?Martin_Vejn=E1r?=)
Date: Mon, 1 May 2006 14:42:08 GMT
Raw View
Greg Herlihy wrote:
> In that case, evaluating this expression:
>
>     a = b = 0;
>
> must also lead to undefined behavior - because it too reads from b "for
> a purpose other than that to determine the value to be stored".  And
> yet this kind of expression appears so frequently in C++ programs that
> it is difficult to imagine that its behavior is, in fact, undefined.

This is a very interesting point. Let's suppose 'a' and 'b' are of a
built-in type. (In case of a class type, there is no problem, as the
assignment is handled by 'operator=' and there is a sequence point at
the moment of call.)

[5.17/1]
     [...] The result of the assignment operation is the value stored in
the left operand after the assignment has taken place; the result is an
lvalue.

I failed to understand what that means. What is the result of an
expression "b = 0"? Is it 'b'? Or is it some kind of a temporary with
value 0? (The value stored in the left operand is 0 - which by itself is
an rvalue. But the result must be an lvalue. Doesn't make much sense to
me...) What is "&(b = 0)"?

If the result was 'b', then the behavior would indeed be undefined (as
explained by Greg Herlihy in the quote above). It would also be
unfortunate as "a = b = ..." is quite common idiom, isn't it?

What will happen in the following case?
(b = 0) = a;

--
Martin

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: usenet-nospam@nmhq.net (Niklas Matthies)
Date: Mon, 1 May 2006 14:42:11 GMT
Raw View
On 2006-05-01 01:50, Victor Bazarov wrote:
> Niklas Matthies wrote:
>> On 2006-04-30 18:40, Greg Herlihy wrote:
>>> James Dennett wrote:
>>>
>>>> It writes to b, and also reads from it for a purpose other
>>>> than that to determine the value to be stored.  By the quote
>>>> above, the behavior is undefined.  It is *not* necessary for
>>>> there to be two writes to an object between sequence points
>>>> for there to be undefined behavior (though it is sufficient).
>>>
>>> In that case, evaluating this expression:
>>>
>>>     a = b = 0;
>>>
>>> must also lead to undefined behavior - because it too reads from b
>>> "for a purpose other than that to determine the value to be stored".
>>
>> FWIW, at least in C this expression doesn't read from b.
>
> What if 'b' is declared 'volatile'?

The value of an assignment expression is defined to be the same value
that the left operand will have after the assignment, period. It's
independent from when the side effect of updating the stored value of
the left operand actually occurs. One way to see it is that the value
to be assigned (i.e. after conversion) is duplicated: one copy becomes
the result of the assignment expression while the other one is stored
in the left operand.

I'm not sure whether an implementation that implements this behavior
by performing an actual read on a volatile left operand would be
conforming. The fact that assignment expressions are not lvalues in C
could be taken as an argument against it.

> What if the type of 'b' is not one of built-ins?

Doesn't make a difference (in C).

-- Niklas Matthies

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: kanze.james@neuf.fr (James Kanze)
Date: Mon, 1 May 2006 14:41:31 GMT
Raw View
Victor Bazarov wrote:
 > Niklas Matthies wrote:
 >> On 2006-04-30 18:40, Greg Herlihy wrote:
 >>> James Dennett wrote:

 >>>> It writes to b, and also reads from it for a purpose other
 >>>> than that to determine the value to be stored.  By the
 >>>> quote above, the behavior is undefined.  It is *not*
 >>>> necessary for there to be two writes to an object between
 >>>> sequence points for there to be undefined behavior (though
 >>>> it is sufficient).
 >>> In that case, evaluating this expression:

 >>>     a =3D b =3D 0;

 >>> must also lead to undefined behavior - because it too reads
 >>> from b "for a purpose other than that to determine the value
 >>> to be stored".

 >> FWIW, at least in C this expression doesn't read from b.

 > What if 'b' is declared 'volatile'?

Doesn't change anything.  Except that the side effects must take
place before the next sequence point.  (Note, for example, that
even if a and b are volatile, no ordering of the writes is
implied.)

 > What if the type of 'b' is not one of built-ins?

Then you have a function call, with additional sequence points.

Note that in certain cases, "a =3D b =3D 0" can be undefined, e.g.:

     int  i ;
     int& a =3D i ;
     int& b =3D i ;
     a =3D b =3D 0 ;             //  Here, it's undefined.

--=20
James Kanze                                    kanze.james@neuf.fr
Conseils en informatique orient=E9e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France +33 (0)1 30 23 00 34

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: ron@spamcop.net (Ron Natalie)
Date: Mon, 1 May 2006 14:41:43 GMT
Raw View
Victor Bazarov wrote:

>>>
>>>     a = b = 0;
>>>
>>> must also lead to undefined behavior - because it too reads from b
>>> "for a purpose other than that to determine the value to be stored".
>> FWIW, at least in C this expression doesn't read from b.
>
> What if 'b' is declared 'volatile'?  What if the type of 'b' is not
> one of built-ins?
>
> V
Volatile has no bearing here.   The right hand side of the
a = ... assignment is NOT b.  it's the result of the the b = 0,
assignment, the "value stored in the left operand".

As for UDT's, if op= is overloaded, it's hard to make any assumptions.
However, it's rare that things get "worse" as overloaded ops usually
introduce 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Mon, 1 May 2006 17:49:30 CST
Raw View
Ron Natalie wrote:
> Victor Bazarov wrote:
>
> >>>
> >>>     a = b = 0;
> >>>
> >>> must also lead to undefined behavior - because it too reads from b
> >>> "for a purpose other than that to determine the value to be stored".
> >> FWIW, at least in C this expression doesn't read from b.
> >
> > What if 'b' is declared 'volatile'?  What if the type of 'b' is not
> > one of built-ins?
> >
> > V
> Volatile has no bearing here.   The right hand side of the
> a = ... assignment is NOT b.  it's the result of the the b = 0,
> assignment, the "value stored in the left operand".

If the b = 0 portion of the expression a = b = 0 is not in fact b, then
where is the value 1 being assigned in the C++ program below:

    #include <iostream>

    int main()
    {
        int b;

        (b = 0) = 1;

        std::cout << "b is " << b << "\n";
    }

The output that I observe ("b is 1") certainly suggests that b = 0
evaluates to nothing other than b itself. And if we agree that the
behavior of this program is undefined because it modifies b twice with
no intervening sequence point, then the original example, a = b = 0,
must also have undefined behavior because it reads from b after having
modified b (again with no intervening sequence point). In other words
the expression a = b = 0 accesses b for a reason other than to store a
new value in b, once we accept that b = 0 evaluates to b.

Note also that this C++ program will not compile as a C program because
in C, b = 0 evaluates to an rvalue, 0.

In fact the issues surrounding sequence points and lvalue-returning
operators in C++ (such as the assignment operator) is an active
language issue - and one that apparently remains unresolved:
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#222

Greg

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "kmarkw65@yahoo.com" <markw65@gmail.com>
Date: Mon, 1 May 2006 18:28:55 CST
Raw View
Greg Herlihy wrote:
> Ron Natalie wrote:
> > Victor Bazarov wrote:
> >
> > >>>
> > >>>     a = b = 0;
> > >>>
> > >>> must also lead to undefined behavior - because it too reads from b
> > >>> "for a purpose other than that to determine the value to be stored".
> > >> FWIW, at least in C this expression doesn't read from b.
> > >
> > > What if 'b' is declared 'volatile'?  What if the type of 'b' is not
> > > one of built-ins?
> > >
> > > V
> > Volatile has no bearing here.   The right hand side of the
> > a = ... assignment is NOT b.  it's the result of the the b = 0,
> > assignment, the "value stored in the left operand".
>
> If the b = 0 portion of the expression a = b = 0 is not in fact b, then
> where is the value 1 being assigned in the C++ program below:
>
>     #include <iostream>
>
>     int main()
>     {
>         int b;
>
>         (b = 0) = 1;
>
>         std::cout << "b is " << b << "\n";
>     }
>
> The output that I observe ("b is 1") certainly suggests that b = 0
> evaluates to nothing other than b itself. And if we agree that the
> behavior of this program is undefined because it modifies b twice with
> no intervening sequence point,

The wording for the semantics of the assignment operator is clearly
flawed (see previous discussions in this forum); but granting that
assumption...

> then the original example, a = b = 0,
> must also have undefined behavior

No.

> because it reads from b after having
> modified b (again with no intervening sequence point).

Note that reading b *after* modifying it does not constitute accessing
the *prior* value.

Mark Williams

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: James Kanze <kanze.james@neuf.fr>
Date: 2 May 2006 02:30:16 GMT
Raw View
Martin Vejn   r wrote:
 > Greg Herlihy wrote:
 >> In that case, evaluating this expression:

 >>     a = b = 0;

 >> must also lead to undefined behavior - because it too reads
 >> from b "for a purpose other than that to determine the value
 >> to be stored".  And yet this kind of expression appears so
 >> frequently in C++ programs that it is difficult to imagine
 >> that its behavior is, in fact, undefined.

 > This is a very interesting point. Let's suppose 'a' and 'b'
 > are of a built-in type. (In case of a class type, there is no
 > problem, as the assignment is handled by 'operator=' and there
 > is a sequence point at the moment of call.)

 > [5.17/1]
 >     [...] The result of the assignment operation is the value
 >     stored in the left operand after the assignment has taken
 >     place; the result is an lvalue.

 > I failed to understand what that means.  What is the result of
 > an expression "b = 0"?  Is it 'b'?  Or is it some kind of a
 > temporary with value 0?  (The value stored in the left operand
 > is 0 - which by itself is an rvalue. But the result must be an
 > lvalue. Doesn't make much sense to me...) What is "&(b = 0)"?

In C, it is the value which is stored.  Because the operand is
an lvalue in C++, the question is a bit more ambiguous, but
presumably, the intent was that what was legal in C has the same
meaning.  It's an interesting case, because we have a case
where the expression is an lvalue, but its "value" is NOT the
result of an lvalue to rvalue conversion.

 > If the result was 'b', then the behavior would indeed be
 > undefined (as explained by Greg Herlihy in the quote above).
 > It would also be unfortunate as "a = b = ..." is quite common
 > idiom, isn't it?

In C, the problem didn't exist, because the results of
assignment weren't an lvalue.  In C++, presumably, the intent is
that using the results in an rvalue context work exactly as it
does in C.

The standard probably needs some clarification here.

 > What will happen in the following case?  (b = 0) = a;

That IS undefined behavior.  Both in C and in C++.

--
James Kanze                                    kanze.james@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




---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: 2 May 2006 02:40:05 GMT
Raw View
kmarkw65@yahoo.com wrote:
> Greg Herlihy wrote:
> > Ron Natalie wrote:
> > > Victor Bazarov wrote:
> > >
> > > >>>
> > > >>>     a = b = 0;
> > > >>>
> > > >>> must also lead to undefined behavior - because it too reads from b
> > > >>> "for a purpose other than that to determine the value to be stored".
> > > >> FWIW, at least in C this expression doesn't read from b.
> > > >
> > > > What if 'b' is declared 'volatile'?  What if the type of 'b' is not
> > > > one of built-ins?
> > > >
> > > > V
> > > Volatile has no bearing here.   The right hand side of the
> > > a = ... assignment is NOT b.  it's the result of the the b = 0,
> > > assignment, the "value stored in the left operand".
> >
> > If the b = 0 portion of the expression a = b = 0 is not in fact b, then
> > where is the value 1 being assigned in the C++ program below:
> >
> >     #include <iostream>
> >
> >     int main()
> >     {
> >         int b;
> >
> >         (b = 0) = 1;
> >
> >         std::cout << "b is " << b << "\n";
> >     }
> >
> > The output that I observe ("b is 1") certainly suggests that b = 0
> > evaluates to nothing other than b itself. And if we agree that the
> > behavior of this program is undefined because it modifies b twice with
> > no intervening sequence point,
>
> The wording for the semantics of the assignment operator is clearly
> flawed (see previous discussions in this forum); but granting that
> assumption...
>
> > then the original example, a = b = 0,
> > must also have undefined behavior
>
> No.
>
> > because it reads from b after having
> > modified b (again with no intervening sequence point).
>
> Note that reading b *after* modifying it does not constitute accessing
> the *prior* value.

Correct. So there are two reasons why the behavior of the expression a
= b = 0 is undefined. First, the value obtained from accessing b is not
used to calculate a new value for b, and second, the value obtained
from b is not in fact the value that b had prior to the assignment of
its current value (that is, the value that b had at the start of the
expression). In other words the expression is undefined since it uses
the wrong value for the wrong reason.

Greg

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Alf P. Steinbach" <alfps@start.no>
Date: Mon, 1 May 2006 23:06:50 CST
Raw View
* Greg Herlihy:
>
> ... there are two reasons why the behavior of the expression a
> = b = 0 is undefined. First, the value obtained from accessing b is not
> used to calculate a new value for b, and second, the value obtained
> from b is not in fact the value that b had prior to the assignment of
> its current value (that is, the value that b had at the start of the
> expression). In other words the expression is undefined since it uses
> the wrong value for the wrong reason.

I think the standard is simply defective /in its definition of
assignment/,    5.17/1, not expressing the intent of C compatibility.

 From a formal point of view there's nothing, AFAICS, that says that
accessing the result of (b=0), an lvalue, in the expression a=b=0, is
not an lvalue to rvalue conversion.  Hence formally this is accessing
the value of b  --  for a purpose other than determining the value to be
assigned  --  and so UB.  Which, if that were the intent, would make
existing practice UB, and so $5/4 would then be defective.

However, if we allow that the intent was C compatibility (as discussed
in active issue 222, which you provided a reference to), then it's just
that part about the assignment operator, not $5/4, that is defective.

Just the same, I wish $5/4 to at least be cleaned up, with more clear
language  --  since experts and very knowledgable programmers can't
agree on what it means, at least not right away.

And preferably, I wish $5/4 to be changed to always yield well-defined
behavior, except e.g. as modified by a backwards-compatibility macro, as
outlined in my first posting in this thread.

It would be interesting to hear whether readers are generally in favor
of, or opposed to, that.  Perhaps it could be possible to convince
enough committee members to Make It Happen? :-)

References:
So far in this thread two relevant defect reports have surfaced:
<url: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#351>,
<url: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#222>.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "kanze" <kanze@gabi-soft.fr>
Date: Tue, 2 May 2006 09:26:32 CST
Raw View
Ron Natalie wrote:
> Victor Bazarov wrote:

> >>>     a = b = 0;

> >>> must also lead to undefined behavior - because it too
> >>> reads from b "for a purpose other than that to determine
> >>> the value to be stored".
> >> FWIW, at least in C this expression doesn't read from b.

> > What if 'b' is declared 'volatile'?  What if the type of 'b' is not
> > one of built-ins?

> > V

> Volatile has no bearing here.   The right hand side of the a =
> ... assignment is NOT b.  it's the result of the the b = 0,
> assignment, the "value stored in the left operand".

This is indiscutably true in C.  I'm fairly sure, too, that the
intent is that C++ behave as does C in this case.  However, the
issue is somewhat clouded by the fact that b = 0 is an lvalue.
Presumably, when we assign it to a, an lvalue to rvalue
conversion occurs -- traditionally, an lvalue to rvalue
conversion is considered the equivalent of reading the lvalue.

I think some clarification might be in order.  I'm pretty sure
that the intent is for C++ to behave as C does here.  I'm less
sure that this is what the C++ really says.

> As for UDT's, if op= is overloaded, it's hard to make any
> assumptions. However, it's rare that things get "worse" as
> overloaded ops usually introduce sequence points.

On the other hand, it affects the volatile.  If the UDT op=
returns a reference (to a volatile), the value in memory will
almost certainly be read.

--
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


---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "mark" <markw65@gmail.com>
Date: 2 May 2006 16:10:20 GMT
Raw View
Greg Herlihy wrote:
> kmarkw65@yahoo.com wrote:
> >
> > > then the original example, a = b = 0,
> > > must also have undefined behavior
> >
> > No.
> >
> > > because it reads from b after having
> > > modified b (again with no intervening sequence point).
> >
> > Note that reading b *after* modifying it does not constitute accessing
> > the *prior* value.
>
> Correct. So there are two reasons why the behavior of the expression a
> = b = 0 is undefined. First, the value obtained from accessing b is not
> used to calculate a new value for b,

Which is not undefined behavior according to anything quoted from the
standard so far. In particular 5/4 states:

. Furthermore, the prior value shall be accessed only to determine
the value to be stored.  The requirements of this paragraph shall
be met for each allowable ordering of the subexpressions of a full
expression; otherwise the behavior is undefined

The prior value is not accessed at all, so this cannot apply.

I concede that it may be undefined for some other reason, but you're
going to have to point me to the relevant part of the standard.

> and second, the value obtained
> from b is not in fact the value that b had prior to the assignment of
> its current value (that is, the value that b had at the start of the
> expression).

Which again, is clearly not forbidden by 5/4. You'll have to tell me
how to derive that from the standard.

Mark Williams

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: johnchx2@yahoo.com
Date: Tue, 2 May 2006 11:43:40 CST
Raw View
Alf P. Steinbach wrote:

>  From a formal point of view there's nothing, AFAICS, that says that
> accessing the result of (b=0), an lvalue, in the expression a=b=0, is
> not an lvalue to rvalue conversion.

Indeed, what else could it be?

> Hence formally this is accessing
> the value of b  --  for a purpose other than determining the value to be
> assigned  --  and so UB.

This, however, is not true.  5/4 says that "...the prior value shall be
accessed only to determine the value to be stored."  5.17/1 says that
"(t)he result of the assignment operation is the value stored in the
left operand after the assignment has taken place...," which guarantees
that evaluating the assignment expression does not access the *prior*
value of the assigned-to variable.

There does seem to be some clever language lawyering in this wording.
The key point to notice is that nothing in the standard guarantees that
an lvalue-to-rvalue conversion must be implemented as a read from the
memory address(es) denoted by the lvalue.  What 5.17/1 is saying is
that the result of the lvalue-to-rvalue conversion applied to an
assignment expression *shall be* the "new" value assigned to the
variable, whether or not the store-to-memory has actually taken place.
This trickery allows us to chain assignments together with well-defined
behavior, without introducing a de facto sequence point between the
assignments.

(That, of course, introduces some strange semantics with respect to
volatile variables...AFAICT, 5.17/1 actually forbids an implementation
in which evaluating b = 1 in an rvalue context yields anything but 1,
even if b is volatile and b has been modified by the external
environment.)

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Alf P. Steinbach" <alfps@start.no>
Date: Tue, 2 May 2006 13:49:02 CST
Raw View
* johnchx2@yahoo.com:
> Alf P. Steinbach wrote:
>
>>  From a formal point of view there's nothing, AFAICS, that says that
>> accessing the result of (b=0), an lvalue, in the expression a=b=0, is
>> not an lvalue to rvalue conversion.
>
> Indeed, what else could it be?
>
>> Hence formally this is accessing
>> the value of b  --  for a purpose other than determining the value to be
>> assigned  --  and so UB.
>
> This, however, is not true.  5/4 says that "...the prior value shall be
> accessed only to determine the value to be stored."  5.17/1 says that
> "(t)he result of the assignment operation is the value stored in the
> left operand after the assignment has taken place...," which guarantees
> that evaluating the assignment expression does not access the *prior*
> value of the assigned-to variable.
>
> There does seem to be some clever language lawyering in this wording.
> The key point to notice is that nothing in the standard guarantees that
> an lvalue-to-rvalue conversion must be implemented as a read from the
> memory address(es) denoted by the lvalue.  What 5.17/1 is saying is
> that the result of the lvalue-to-rvalue conversion applied to an
> assignment expression *shall be* the "new" value assigned to the
> variable, whether or not the store-to-memory has actually taken place.
> This trickery allows us to chain assignments together with well-defined
> behavior, without introducing a de facto sequence point between the
> assignments.

The possibility of not accessing does not guarantee not accessing.  By
the logic that the possibility of not accessing is enough to resque the
expression from undefinedness, the original expression (a = (a + b) - (b
= a)) must be well-defined.  For also here we have the possibility of an
evaluation that doesn't access the prior value of b for a purpose other
than determining the stored value.

Tricky, indeed! :-)

Can we agree that when it's /that/ tricky, it needs some fixing?  Well,
anyway, it already has an active issue, 222.  So perhaps it'll be fixed.


> (That, of course, introduces some strange semantics with respect to
> volatile variables...AFAICT, 5.17/1 actually forbids an implementation
> in which evaluating b = 1 in an rvalue context yields anything but 1,
> even if b is volatile and b has been modified by the external
> environment.)

I think that's a case of any conclusion following from an inconsistent
premise... ;-)


--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: johnchx2@yahoo.com
Date: 2 May 2006 20:50:01 GMT
Raw View
Alf P. Steinbach wrote:

> * johnchx2@yahoo.com:
>
> > This trickery allows us to chain assignments together with well-defined
> > behavior, without introducing a de facto sequence point between the
> > assignments.
>
> The possibility of not accessing does not guarantee not accessing.

I think you misunderstand me.  The standard *does* guarantee that
evaluating an assignment expression in an rvalue context does not
access the prior value of the assigned-to variable.  That is what
5.17/1 says.

Given:

 int a = 0;
 int b = 1;
 a = b = 2;  // line A

There is no order of evaluation of the expression in Line A which is
both (a) permitted by the standard and (b) accesses the prior value of
b (i.e. 1).

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: alfps@start.no ("Alf P. Steinbach")
Date: Wed, 3 May 2006 03:41:08 GMT
Raw View
* johnchx2@yahoo.com:
> Alf P. Steinbach wrote:
>
>> * johnchx2@yahoo.com:
>>
>>> This trickery allows us to chain assignments together with well-defined
>>> behavior, without introducing a de facto sequence point between the
>>> assignments.
>> The possibility of not accessing does not guarantee not accessing.
>
> I think you misunderstand me.  The standard *does* guarantee that
> evaluating an assignment expression in an rvalue context does not
> access the prior value of the assigned-to variable.  That is what
> 5.17/1 says.
>
> Given:
>
>  int a = 0;
>  int b = 1;
>  a = b = 2;  // line A
>
> There is no order of evaluation of the expression in Line A which is
> both (a) permitted by the standard and (b) accesses the prior value of
> b (i.e. 1).

Uhum, I think you're on to something (I know, I'm vacillating wildly,
but there are good arguments on all three sides...)

But that interpretation seems to be equivalent to a sequence point.

If I now understand this correctly, 5.17/1 implicitly says that the
evaluation sequence

    int& r = b;    // The effective formal result of (b=2).
    a = r;
    b = 2;

is not permitted in spite of (b=2) being an lvalue, that the right hand
side of an assignment /must/ be fully evaluated before updating the
object specified by the left hand side.

Furthermore, if I understand this correctly, it implicitly says that the
translation

    b = 2;
    a = b;

is not permitted for volatile b, but rather something like

    int const __temp = 2;
    b = __temp;
    a = __temp;

must be employed (in practice with __temp a processor register).

So, the remaining issue in interpreting the current wording: how is that
very strict sequence-defining restriction different from having a
sequence point, and

how is it different from what you call "a de facto sequence point",
which we can do "without"  --  isn't it there?


PS: As mentioned, I think this needs fixing.  It shouldn't be that unclear.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: house@usq.edu.au (Ron House)
Date: Wed, 3 May 2006 03:41:15 GMT
Raw View
Alf P. Steinbach wrote:

>  From a formal point of view there's nothing, AFAICS, that says that
> accessing the result of (b=0), an lvalue, in the expression a=b=0, is
> not an lvalue to rvalue conversion.  Hence formally this is accessing
> the value of b  --  for a purpose other than determining the value to be
> assigned  --  and so UB.  Which, if that were the intent, would make
> existing practice UB, and so $5/4 would then be defective.

Okay, what about:

int a; int *p;
p = &(a = 0);
*p = 1;

If (a = 0) yields an lvalue, I should be able to take its address? The
only question remains, it that address the address of a? If so, where
does it say that?

--
Ron House       house@usq.edu.au
                 http://www.sci.usq.edu.au/staff/house

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: johnchx2@yahoo.com
Date: Wed, 3 May 2006 09:56:21 CST
Raw View
"Alf P. Steinbach" wrote:

> If I now understand this correctly, 5.17/1 implicitly says that the
> evaluation sequence
>
>     int& r = b;    // The effective formal result of (b=2).
>     a = r;
>     b = 2;
>
> is not permitted in spite of (b=2) being an lvalue, that the right hand
> side of an assignment /must/ be fully evaluated before updating the
> object specified by the left hand side.

Not exactly.  The evaluation sequence above is not equivalent to

  a = b = 2;

because r is not equivalent to (b = 2) -- in particular, if converted
to an rvalue, it isn't guaranteed to yield the new value of b.  In
other words, (b=2) is an lvalue, but it's not quite the lvalue you
might think it is.  Let's call it B, just to give it a name.  B has two
guaranteed properties:

  &B == &a;   // true, would hold of r
  B == 2;      // true, would not necessarily hold of r

The difference between this guarantee (call it "B, the Magic Lvalue")
and a real sequence point is that the following guarantee isn't
offered:

  *(&(B)) == 2;  // might or might not be true

Which means that *(&(B)) == B might not hold.  Nor is any other
lvalue-to-rvalue conversion applied to b within the same expression
guaranteed to evaluate to 2.  5.17/1 only tells us what we get from
evaluating (b = 2).

The implementation is free to delay the side effect -- actually writing
the value 2 to the memory denoted by b -- as long as it meets the
requirement that evaluating (b = 2) as an rvalue yields the new value.


>
> Furthermore, if I understand this correctly, it implicitly says that the
> translation
>
>     b = 2;
>     a = b;
>
> is not permitted for volatile b, but rather something like
>
>     int const __temp = 2;
>     b = __temp;
>     a = __temp;
>
> must be employed (in practice with __temp a processor register).
>

Yes, I think that's what it says.  I'm not sure that's quite what the
committee *wants* it to say, but it does seem to be what it says.

> So, the remaining issue in interpreting the current wording: how is that
> very strict sequence-defining restriction different from having a
> sequence point, and
>
> how is it different from what you call "a de facto sequence point",
> which we can do "without"  --  isn't it there?

I think the difference is that the side effect need not actually take
place until some later point, and that nothing is guaranteed about what
you'll get when reading the value of b by some other route than the
evaluation of (b = 2) within the same 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: fisker0303@126.com
Date: Thu, 27 Apr 2006 11:16:30 CST
Raw View
===================================== MODERATOR'S COMMENT:

I'm approving this for an odd reason. This question isn't quite
on-topic because it doesn't directly deal with the C++ standard,
but many of the possible answers to the question do directly
deal with the C++ standard. Let's make sure to keep followups
focused appropriately.

------=_Part_4136_31897272.1146154564994
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

approve<br>comment<br>I'm approving this for an odd reason. This question i=
sn't quite <br>on-topic because it doesn't directly deal with the C++ stand=
ard,<br>but many of the possible answers to the question do directly <br>
deal with the C++ standard. Let's make sure to keep followups <br>focused a=
ppropriately.<br>

------=_Part_4136_31897272.1146154564994--


===================================== END OF MODERATOR'S COMMENT
In vc 6.0:

#include <iostream>
using namespace std;

int main()
{
        int a = 10;
        int b = 20;
        a = (a + b) - (b = a);
        cout << "a=" << a << ",b=" << b << endl;
        return 0;

}

Release output : a=20,b=10
Debug output: a=10,b=10

why?

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: loufoque <loufoque@remove.gmail.com>
Date: Thu, 27 Apr 2006 20:56:46 CST
Raw View
fisker0303@126.com wrote :

> In vc 6.0:

Be aware that Microsoft Visual Studio 6.0 is totally outdated and has
pretty bad support of Standard C++.
Yet, your problem isn't related to that fact at all : this is not a bug.


>         a = (a + b) - (b = a);

That line is undefined behaviour.
C++ doesn't specify in which order the operations should be done.

a could contain 20 if a+b is computed first and 10 if b=a is computed first.


> Release output : a=20,b=10
> Debug output: a=10,b=10
>
> why?

When invoking undefined behaviour you shouldn't expect something well
defined.

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Alf P. Steinbach" <alfps@start.no>
Date: Thu, 27 Apr 2006 20:57:55 CST
Raw View
First, re moderation policy:

> ===================================== MODERATOR'S COMMENT:
>
> I'm approving this for an odd reason. This question isn't quite
> on-topic because it doesn't directly deal with the C++ standard,
> but many of the possible answers to the question do directly
> deal with the C++ standard. Let's make sure to keep followups
> focused appropriately.
>
> ------=_Part_4136_31897272.1146154564994
> Content-Type: text/html; charset=ISO-8859-1
> Content-Transfer-Encoding: quoted-printable
> Content-Disposition: inline
>
> approve<br>comment<br>I'm approving this for an odd reason. This question i=
> sn't quite <br>on-topic because it doesn't directly deal with the C++ stand=
> ard,<br>but many of the possible answers to the question do directly <br>
> deal with the C++ standard. Let's make sure to keep followups <br>focused a=
> ppropriately.<br>
>
> ------=_Part_4136_31897272.1146154564994--
>
> ===================================== END OF MODERATOR'S COMMENT

I suggest that the group's FAQ and/or moderation guidelines should
include, in addition to the FAQ's current reference to RFC 1855:

* preferentially don't post with quoted printable encoding (QP is for
e-mail, not news),

* preferentially don't post HTML, and

* preferentially don't post multi-part messages.

But as evidently happened here, such settings can be applied by mistake,
or via too "helpful" software.  Is it perhaps possible to automatically
detect & reject "Content-Type: text/html" and
"Content-Transfer-Encoding: quoted-printable"?


* fisker0303@126.com:
> In vc 6.0:
>
> #include <iostream>
> using namespace std;
>
> int main()
> {
>         int a = 10;
>         int b = 20;
>         a = (a + b) - (b = a);
>         cout << "a=" << a << ",b=" << b << endl;
>         return 0;
>
> }
>
> Release output : a=20,b=10
> Debug output: a=10,b=10
>
> why?

Why you get that output: C++ does not generally guarantee the evaluation
order of an expression (the built-in boolean operators are exceptions),
and so (as I see it) the expression has unspecified effect: either 'b=a'
is evaluated before 'a+b', or after, at the compiler's discretion.

If it were 'a' being modified, the behavior would not (IMO) be merely
unspecified, but undefined, which is much worse.  But the examples in
the standard, para    5/4, say "unspecified" where the normative text says
"undefined", so there was evidently some confusion back in 1998.  That
has already been fixed; Tom Widmer once directed me to <url:
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#351>.

I think the intention had to be that also in the case above the effect
should be undefined, so I think that    5/4 should either be fixed to
include the case above as undefined behavior, or be changed to yield
well defined, deterministic behavior.

Why it is like that: once, very long ago, say, around 1972, computers
were really slow.  So /a constant factor/ of improved efficiency
mattered a lot; even a marginal improvement could be crucial.  And the
computers were also rather primitive, so much so that the compiler's
detailed machine code optimization of expressions directly influenced
efficiency at this level (the hardware didn't do predictive and parallel
execution and such things).  So, the more freedom the compiler had to
reorder things in a then "optimal" way, the better for efficiency.

So in C++, for historical reasons, we pay the price, again and again,
but except possibly in embedded systems don't ever get the goods  --
they no longer exist, in practice.

Today it seems the 80 to 90% consensus is that deterministic evaluation,
that you can always predict at the "as-if" level which operations will
be executed in which order, matters much much more than whatever
now-really-marginal-if-any improvement of efficiency can be had via free
reordering of expressions.  At a slightly more abstract level, namely
reordering of statement execution order under "as-if" rules, as I
understand it it's also desirable for multi-threaded programming.  E.g.,
Sutter and Alexandrescu (I think it was) once wrote an article about why
the double-locking pattern isn't supported by current C++.

The problems, as I see them, are that (1) changing the standard in this
respect would probably break a lot of existing code, and (2) it might
--  I don't know  --  be problematic for embedded systems programming.

One solution to problem (1) is to say, so what, let's break that code
(after all, it's probably maintained using some old compiler that won't
be upgraded precisely to keep the code working); that was done in 1998.

Another solution to (1) is to e.g. define a macro symbol that specifies
the old unpredictable behavior, say, __UNPREDICTABLE__ (or, after the
marketing department has had its say, __ULTRA_EFFICIENT__), so that for
new compilers, deterministic behavior is by default.  This solution has
the advantage of keeping C++ as a practical efficient-enough language
for embedded systems programming, if that actually is a problem.  I.e.,
it also solves the hypothetical problem (2).

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "ThosRTanner" <ttanner2@bloomberg.net>
Date: Fri, 28 Apr 2006 09:36:45 CST
Raw View
Alf P. Steinbach wrote:
<snip>
>
> The problems, as I see them, are that (1) changing the standard in this
> respect would probably break a lot of existing code, and (2) it might
> --  I don't know  --  be problematic for embedded systems programming.
>
> One solution to problem (1) is to say, so what, let's break that code
> (after all, it's probably maintained using some old compiler that won't
> be upgraded precisely to keep the code working); that was done in 1998.
>
> Another solution to (1) is to e.g. define a macro symbol that specifies
> the old unpredictable behavior, say, __UNPREDICTABLE__ (or, after the
> marketing department has had its say, __ULTRA_EFFICIENT__), so that for
> new compilers, deterministic behavior is by default.  This solution has
> the advantage of keeping C++ as a practical efficient-enough language
> for embedded systems programming, if that actually is a problem.  I.e.,
> it also solves the hypothetical problem (2).

As far as embedded systems go, when I was programming for them,
(a) Never changed the compiler without thorough testing - we had a
certain amount of code that was written to get round compiler optimiser
bugs!
(b) Any UB was a no-no because our code had to run on multiple targets,
even though embedded.
(c) If the compiler was provably not fast enough, rewrite the code in
assembler.
(d) Most code was developed with debugging switched on and then it was
switched off for release testing. A change in behaviour at that point
would be considered unhelpful to say the least.

Which probably means that the most likely people to be affected are
those that:
1) Use only 1 compiler
2) Continually upgrade it
3) Require maximal optimisation

I think the __UNPREDICTABLE__ macro should require that when set, it
diagnosed code which might behave differently if it wasn't set.

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Momchil Velikov" <momchil.velikov@gmail.com>
Date: Fri, 28 Apr 2006 09:36:29 CST
Raw View
Alf P. Steinbach wrote:
> * fisker0303@126.com:
> > In vc 6.0:
> >
> > #include <iostream>
> > using namespace std;
> >
> > int main()
> > {
> >         int a = 10;
> >         int b = 20;
> >         a = (a + b) - (b = a);
> >         cout << "a=" << a << ",b=" << b << endl;
> >         return 0;
> >
> > }
> >
> > Release output : a=20,b=10
> > Debug output: a=10,b=10

> If it were 'a' being modified, the behavior would not (IMO) be merely
> unspecified, but undefined, which is much worse.

The behavior is *undefined*, because the expression "a = (a + b) - (b =
a);"
violates "5. Expressions" [#4]:

"...  Furthermore, the prior value shall be accessed only to determine
      the value to be stored.  The requirements of this paragraph shall
     be met for each allowable ordering of the subexpressions of a full
     expression; otherwise 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "kmarkw65@yahoo.com" <markw65@gmail.com>
Date: Fri, 28 Apr 2006 10:55:15 CST
Raw View
Alf P. Steinbach wrote:

> * fisker0303@126.com:
> > In vc 6.0:
> >
> > #include <iostream>
> > using namespace std;
> >
> > int main()
> > {
> >         int a = 10;
> >         int b = 20;
> >         a = (a + b) - (b = a);
> >         cout << "a=" << a << ",b=" << b << endl;
> >         return 0;
> >
> > }
> >
> > Release output : a=20,b=10
> > Debug output: a=10,b=10
> >
> > why?
>
> Why you get that output: C++ does not generally guarantee the evaluation
> order of an expression (the built-in boolean operators are exceptions),
> and so (as I see it) the expression has unspecified effect: either 'b=a'
> is evaluated before 'a+b', or after, at the compiler's discretion.
>
> If it were 'a' being modified, the behavior would not (IMO) be merely
> unspecified, but undefined, which is much worse.

It makes no difference. Its already undefined. The prior value of b
*could* be used (depending on the ordering of subexpressions). If it is
used, then its certainly not to determine the value stored. So, (modulo
the non-normative examples in 5/4), the behavior is undefined.

Mark Williams

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Fri, 28 Apr 2006 13:17:11 CST
Raw View
Momchil Velikov wrote:
> Alf P. Steinbach wrote:
> > * fisker0303@126.com:
> > > In vc 6.0:
> > >
> > > #include <iostream>
> > > using namespace std;
> > >
> > > int main()
> > > {
> > >         int a = 10;
> > >         int b = 20;
> > >         a = (a + b) - (b = a);
> > >         cout << "a=" << a << ",b=" << b << endl;
> > >         return 0;
> > >
> > > }
> > >
> > > Release output : a=20,b=10
> > > Debug output: a=10,b=10
>
> > If it were 'a' being modified, the behavior would not (IMO) be merely
> > unspecified, but undefined, which is much worse.
>
> The behavior is *undefined*, because the expression "a = (a + b) - (b =
> a);"
> violates "5. Expressions" [#4]:
>
> "...  Furthermore, the prior value shall be accessed only to determine
>       the value to be stored.  The requirements of this paragraph shall
>      be met for each allowable ordering of the subexpressions of a full
>      expression; otherwise the behavior is undefined."

No, the behavior is merely unspecified - not undefined. In other words,
the variable "a" is certain to have either the value 20 or the value 10
after the expression is evaluated.

The expression would have to store a value in either "a" or "b" more
than once for it to have undefined behavior.

Greg

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: fisker0303@126.com
Date: Fri, 28 Apr 2006 22:03:47 CST
Raw View
Thanks a lot.I got 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "kmarkw65@yahoo.com" <markw65@gmail.com>
Date: 29 Apr 2006 20:30:02 GMT
Raw View
Greg Herlihy wrote:
> Momchil Velikov wrote:

> >
> > The behavior is *undefined*, because the expression "a = (a + b) - (b =
> > a);"
> > violates "5. Expressions" [#4]:
> >
> > "...  Furthermore, the prior value shall be accessed only to determine
> >       the value to be stored.  The requirements of this paragraph shall
> >      be met for each allowable ordering of the subexpressions of a full
> >      expression; otherwise the behavior is undefined."
>
> No, the behavior is merely unspecified - not undefined. In other words,
> the variable "a" is certain to have either the value 20 or the value 10
> after the expression is evaluated.
>
> The expression would have to store a value in either "a" or "b" more
> than once for it to have undefined behavior.

That is, indeed, one of the many, many things that invoke undefined
behavior; but the fact that this code doesnt do that is not sufficient
to make its behavior defined.

In fact, since the code violates the "shall" in 5/4 (which you quoted
above), it *does* invoke undefined behavior.

Mark Williams

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]