10

I'm still slightly confused after reading this topic. Is the following C++ expression *d++ = ~(*d); well defined? Yes, I know compound expressions like this are ugly.. I didn't write it.

I see a slight difference in the generated assembly when I compare it to:

*d = ~(*d);
d++;

Assembly:

*d++ = ~(*d);
0x83384    LDR           R3,[R0 <d>,4]        <<diff
0x83388    ADD           R1 <c>, R1 <c>, 1
0x8338c    MVN           R3, R3
0x83390    STR           R3,[R0 <d>],4

vs

*d = ~(*d);
d++;
0x83384   LDR           R3,[R0 <d>]
0x83388   ADD           R1 <c>, R1 <c>, 1
0x8338c   MVN           R3, R3
0x83390   STR           R3,[R0 <d>],4

Thanks!

Community
  • 1
  • 1
Mav3rick
  • 776
  • 1
  • 7
  • 22
  • All the assembler is going to tell you is what this particular version of this particular compiler did with the settings you used this particular time. It says nothing of what is guaranteed or not by the standard. – Mark Ransom May 16 '11 at 22:25
  • Thanks. I initially thought it might be helpful to see what was being generated by the compiler in the context of this question. I now see that anything(in the undefined case) could have potentially been generated. – Mav3rick May 16 '11 at 22:42

3 Answers3

11

Your expression has undefined (as opposed to unspecified) behavior. The assembly code could as well play Beethoven 9th and still conform to the standard.

From the Holy Standard, Chapter 5, Verse 4:

Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression.

Therefore, the code is ill-formed. I don't know whether a standard conforming compiler is required to issue a diagnostic, but I have been bitten enough times by this that I'm ready to bet it is not.

Refer to @Prasoon Saurav's excellent exposition there for more details.

Community
  • 1
  • 1
Alexandre C.
  • 55,948
  • 11
  • 128
  • 197
  • *THAT* would be pretty damn awesome! :) – FrustratedWithFormsDesigner May 16 '11 at 21:13
  • @coward downvoter: please clarify your intentions. I'm pretty sure it is UB per the link OP pointed to, but I could be wrong. – Alexandre C. May 16 '11 at 21:15
  • 3
    I'd prefer Wagner - Ride of the Valkyries, please! –  May 16 '11 at 21:15
  • 1
    Can you explain more precisely how it's UB? Is it because either `d` or `d+1` may be used on the right side of the assignment? – Mark B May 16 '11 at 21:17
  • @Neil: you are free to write your own standard conforming compiler :) – Alexandre C. May 16 '11 at 21:17
  • Hasn't this been gone through here ad nauseam? –  May 16 '11 at 21:17
  • @Neil: Yes. There is an excellent faq entry about it I linked to. – Alexandre C. May 16 '11 at 21:20
  • 2
    @BoPersson: That's not the reason. `d` gets incremented, the thing that `d` points to is assigned to, these are two different objects. The issue is that there is no sequence point between the increment of `d` and the read of `d` on the rhs of the expression which is a read which is not soley to determine the value being written to `d` in the increment operation. – CB Bailey May 16 '11 at 21:30
  • @Neil I like sitting in my evil lair and playing Toccata and Fugue on "Human Organs". – Mateen Ulhaq May 16 '11 at 23:25
9
*d++ = ~(*d);

In this expression no object is having a new value stored to it more that once. The value of d + 1 is stored to d as a side effect of the incremement operator (d++) and the value of the object pointed to by d before this increment is written to by the assignment operator.

The issue is that d is read, not merely to determine the value to be written back to it (i.e. d + 1) but is also read to determine the address to read from in the right hand side sub-expression ~(*d).

This violates the third sentence of ISO/IEC 14882:2003 5 [expr] / 4 (first sentence omitted for brevity):

[...] Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
1

You just do not know when the ++ gets evaluated. I suppose your compiler evaluates it before the ~(*d) which results in

*d = ~(*(d+1));

thus your dicrepancy.

Christian Rau
  • 45,360
  • 10
  • 108
  • 185
  • Don't suppose anything. There is nothing to suppose, the code is ill formed according to C++ ISO standard. – Alexandre C. May 16 '11 at 21:23
  • I think you meant *d=~(*(d+1)) if you are referring to the ++ taking effect before the rhs lookup. – Jose_X May 16 '11 at 21:58
  • @Alexander C., I think Christian was saying that the disassembly example shows that some particular compiler did the increment first, and this would be different than assembly (or expectation) of the opposite ordering. – Jose_X May 16 '11 at 22:02
  • @Alexandre That was exactly my point. You just do not know what the compiler evalueates first. I just wanted to give him an explanation why the result is different from his assumption. – Christian Rau May 16 '11 at 22:16
  • @Jose_X Yes you're right, first the ++, then the *. I will edit it. – Christian Rau May 16 '11 at 22:18