开发者

Is this "*ptr++ = *ptr + a" undefined behavior?

Well, I'm not really in serious need of this answer, I am just inquisitive.

Expressions like *ptr++ = a are perfectly valid since we are operating on two objects ptr and *ptr but if i write *ptr++ = *ptr + a is it still valid ?

For example consider the following snippet:

int main(void){
   int a[] = {5,7,8,9,2};

   int* p =a;

   *p++ = 76; /*altering 开发者_Python百科the first element */
   *p++ = *p + 32; /*altering the second element */    

   p = a;
   int i;
   for(i = 0;i<5; i++)
      printf("%d ",*p++);

   return 0;
}

I think that there is nothing to worry about with the expression *p++ = *p + 32; but I am unsure about the sequence points involved.


The result of *ptr++ = *ptr + a is undefined. The equals sign is not a sequence point, so using the value of ptr again in that statement results in undefined behavior. Just consider the result if ptr is incremented before the RHS expression is evaluated, and compare it with the case where ptr is incremented after the RHS expression.

Note: this is not to say that the result of the expression will be from either of those two scenarios. Undefined is undefined.

Basically, you can only count on two things: that the post-increment is evaluated some time between the last sequence point and the next one, and that the expression ptr++ returns the value of ptr before it is incremented. So *ptr++ = a is fine because you can count on the result of ptr++.


First let us assume that 'p' is a pointer type.
Otherwise all the operation are just syntactic sugar for function calls.

Lets us break the statement down into parts.

int* p = a;

*p++ = *p + 32;

<< Sequence Point >>
// Part 1: p++
// Note the definition of post increment in the standard is (5.2.6)
// The result of the expression p++ is the value of 'p' while the value of the 
// objects represented by 'p' is incremented. This can be represented in pseudo code as:
(A) int*  p1 = p;
(B) p = p + 1;

// Part 2: *p (On the result of Part 1) (On *p++)
(C) int& p2 = *p1;  // Note the use of p1;

// Part 3: *p (On *p + 32)
// Note: There is no linkage between this use of 'p' and the 'p' in Part 1&2
(D) int& p3 = *p;

// Part 4: *p + 32;
(E) int p5 = p3 + 32; // Note the use of p3;

// Part 5: Assignment.
(F) p2 = p5;
<< Sequence Point >>

Ordering that must be preserved:
(A) Before (B)
(A) Before (C)
(D) Before (E)
(C) Before (F)
(E) Before (F)

Given the above constraints:
The compiler can re-order those instructions in several ways,
But the main point to note is that (B) can happen anywhere the only constraint on (B) is that it happen after (A) Thus the value of p3 as defined in (D) could be one of two different values depending on the exact position of (B).

As the value of p3 can not be defined here.
The resulting statement has undefined behavior.


In terms of C, *ptr++ = *ptr + 32 would be undefined per 6.5.2: "If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined." You're both modifying and attempting to use the value of ptr in another computation without an intervening sequence point.


I think it is undefined. However I'm not certain.

But, a bit of a broader stylistic point: if an expression makes you start to wonder if it's undefined, maybe this is a sign your code is not clear about its intentions and needs to be less ambiguous, and have fewer non-obvious dependencies on order of evaluation.

I used to think C was really cool because you could write a lot of very short statements that do lots of crazy stuff. I don't think that way anymore. :-)


There are not the same if that what you're asking. It will compile though...

It is legal - if PTR points to an array, and not on the last cell of that array, so incrementing PTR will point to the next object in the array.

*ptr++ = *ptr + 2 is the same as *ptr = *ptr + 2, ptr++

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜