Subject: Re: problem in C++ pointer
From: "Jay Krell" <[email-masked]>
To: "Bernard Dautrevaux" <[email-masked]>
Cc: "swe sd" <[email-masked]>, <[email-masked]>
Date: Mon, 13 Mar 2000 02:09:53 -0800

Bernard, we are in agreement though your facts are more complete as to
exactly where the sequence points are. My wording was perhaps confusing.

>> I do not yet know if this code is undefined, but certainly
>> the outcome of
>> code like
>> i = i++;
>> i = ++i;
>> i = i--;
>> i = --i;
>> printf("%d%d", i, ++i);
>> printf("%d%d", --i, ++i);
>> etc.
>>
>> is.
>NO it isn't!... In "printf("%d%d", i, ++i);" and "printf("%d%d", --i,
++i);"
>you do NOT know in which order the parameters of printf are evaluated; note
>that this order can be, and often is, different between both calls to
>printf.

I was saying that it is undefined, not that it is defined..

 - Jay

-----Original Message-----
From: Bernard Dautrevaux <[email-masked]>
To: 'Jay Krell' <[email-masked]>; swe sd <[email-masked]>
Cc: [email-masked] <[email-masked]>
Date: Monday, March 13, 2000 1:54 AM
Subject: RE: problem in C++ pointer

>> -----Original Message-----
>> From: Jay Krell [mailto:[email-masked]]
>> Sent: Sunday, March 12, 2000 9:09 AM
>> To: swe sd
>> Cc: [email-masked]
>> Subject: Re: problem in C++ pointer
>>
>>
>> The behavior at a different time and place of code with
>> undefined behavior
>> is not entirely relevant. Different processors, different
>> command lines,
>> different optimizations (possibly processor specific),
>> different versions,
>> can lead to different definitions of undefined behavior.
>> Still, sometimes
>> undefined behavior is predictable.
>>
>> I do not yet know if this code is undefined, but certainly
>> the outcome of
>> code like
>> i = i++;
>> i = ++i;
>> i = i--;
>> i = --i;
>> printf("%d%d", i, ++i);
>> printf("%d%d", --i, ++i);
>> etc.
>>
>> is.
>
>NO it isn't!... In "printf("%d%d", i, ++i);" and "printf("%d%d", --i,
++i);"
>you do NOT know in which order the parameters of printf are evaluated; note
>that this order can be, and often is, different between both calls to
>printf.
>
>Thus if i == 5, "printf("%d%d", i, ++i);" can display either "56" or "66",
>then i == 6, then "printf("%d%d", --i, ++i);" can display either "56" or
>"76" and then i is still 6.
>
>Note that this is the same case if you wite "j = (--i)*(++i);"; you have no
>clear Idea of what you'll get :-)...
>
>In C and C++ there is only FOUR points where sequencing of operations is
>guaranteed (and only as far as the final result is concerned, not memory
>accesses in some cases):
>1)  Between instructions (that is at each occurence of a semicolon or
>closing brace)
>2)  Between the evaluation of the left-hand-side (lvalue) of an "=", "." or
>"->" operator and the actual access to the refered-to lvalue (assignement
to
>it, or access to a member of, including call of a member function)
>3)  Between the evaluation of all the parameters of a function and its
call,
>and between the actual use of the returned value (store or use in an
>expression) and any other code (that mean that calling the function and
>using the result is implicitely atomic)
>4)  At short-circuit operators (|| and &&) where the left expression is
>evaluated before the  right one.
>5)  At each comma operator; be be VERY careful: the comma operator is NOT
>the same as the comma used to separate arguments of a function call. The
>comma operator is separating two expresseions that are evaluated in order
>(first the left one, then the right one), then the comma operator DISCARDS
>the result of the left expression and yields the value of the right one.
>
>Apart form these cases (and for the sub-expressions of a short-circuit or
>comma operator) the order of evaluation of the components of an expression
>is NOT defined and may change due to very obscure reasons known only by the
>compiler (as the number of registers needed to evaluate an expression or
>store its result, or the need to keep some intermediate non-changing value
>for further use in a subsequent instruction).
>
>> If it isn't clear if code falls into this pattern, that's probably
>> enough reason to not write code like it. But even so, if it
>> is defined, it
>> is a bug if Gcc doesn't consistently give it the standard definition.
>
>The code pattern above IS undefined, thus can give you ANY result, even the
>right one :-)
>
>>
>> Here's a good imho boiled down example:
>> class X
>> {
>> public:
>>     X* F(int i) { printf("%d", i); return this;}
>> };
>>
>> int i = 0;
>> X x, *px = &x;
>> px->F(i++)->F(i++)->F(i++);
>>
>> is the expected output 012 or is it undefined?
>
>This is undefined;
>
>> Could it reasonably be 000, if none of the storages occur
>> till after all
>> parameters are evaluated but before any functoins are called?
>
>It could NOT be 000, as (form C++ point of view) i++ directly change the
"i"
>variable, be it in memory or elsewhere; so it could be 012, 021, 120, 102,
>210, or 201 but nothing else (I think its enough :-))
>
>>
>> according to the parts of the standard I can find and decipher:
>> [expr] 5.0.2: "..uses of overloaded operators are transformed
>> into function
>> calls as described in 13.5. Overloaded operators obey rules for syntax
>> specifidd in this clause, but the requirements of operand
>> type, lvalue, and
>> evaluation order are replaced by the rules for function call".
>>
>> I couldn't find the evaluation order for function calls except
>>
>> [intro.execution]1.8.17 "..There is also a sequence point
>> after the copying
>> of a returned value and before the execution of any
>> expressions outside the
>> function". I don't know if that "copying of a returned value"
>> applies to
>> pointers and references, and I find "expressions outside the function"
>> unclear.
>
>This is needed in C++ as copying the result may need implicitely calling an
>user defined cast operator or copy constructor and that avoiding incorrect
>evaluation order dependencies could be very difficult.
>
>>
>> Ordinarily, the sides of a -> I don't believe have a defined order of
>> evaluation:
>
>They have one although a quite trivial one: the left side of "->" have to
be
>evaluated BEFORE the call can be placed, but the ARGUMENTS of the call can
>be evaluated BEFORE, AFTER, or INTERMIXED with the evaluation of the left
>part of "->".
>
>>
>> eg:
>> class C
>> {
>> public:
>> int i;
>> C(int i) { this->i = i ; }
>> void F(C* c) { printf("%d%d", this->i, c->i); }
>> };
>>
>> C carray[2] = { C(0), C(1) };
>> C* pc = carray;
>>
>> (pc++)->F(pc++);
>>
>> Is the output defined?
>
>No, the order of the two "pc++" is undefined.
>
>> It could "reasonably" be
>> 01
>> 10
>
>Yes
>
>> 00
>
>I don't think so; this would mean parallelizing the two "p++", thus
breaking
>their implicit character of atomicity.
>
>> ?
>>
>> I'm assuming the order of eval of an unoverloaded -> is the same, if
>> defined, as the order of eval of ".".
>
>Yes.
>
>>
>> "sequence point" is not in the index..
>>
>>  - Jay
>>
>
>Note that all this is quite intricated and was explicitely left undefined
to
>allow the optimizer to do its work. There is only one rule to follow: NEVER
>modify the same variable twice in the same instruction.
>
>If you NEED such a construct, introduce intermediate variables and remove
>the offending order dependency. Note that IIRC gcc with "-Wall" will warn
>you of these incorrect order dependencies (among lots of other dubious
>constructs ;->).
>
>Hope this helps,
>
> Bernard
>
>--------------------------------------------
>Bernard Dautrevaux
>Microprocess Ingéniérie
>97 bis, rue de Colombes
>92400 COURBEVOIE
>FRANCE
>Tel: +33 (0) 1 47 68 80 80
>Fax: +33 (0) 1 47 88 97 85
>e-mail: [email-masked]
> [email-masked]
>--------------------------------------------

--
Want to unsubscribe from this list?
Send a message to [email-masked]