Is modifying the pointed value and the pointer at the same time UB

I know that C and C++ and different languages, but the following applies to both.

TL/DR

I know that i = i++; is UB, because i is modified twice in the expression and C and C++ forbids it.

References :

C99 6.5 :

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. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings

C++ 11 - 1.9 15 :

If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, and they are not potentially concurrent, the behavior is undefined.

So I understand that *i = *i++ + *j++; causes UB, because post incrementation on i and affectation to *i may be unsequenced, and CLang issues a warning in C or C++ mode : warning: unsequenced modification and access to 'i' [-Wunsequenced] *i = *i++ + *j++;

But I do not understand the same warning on *i++ = *i + *j++; . Because here, we first compute the right part, affect it, and increment after the affectation.

And specs for both language say (same paragraph, just above) :

The value computations of the operands of an operator are sequenced before the value computation of the result of the operator

END TL/DR

So the question is :

Is this line

*i++ = *i + *j++;

undefined behaviour, or is Clang (version 3.4.1) too conservative in issuing a warning on it ?


The reason both

*i = *i++ + *j++;

and

*i++ = *i + *j++;

are undefined is that you are attempting to use the pointer i in an expression that's a value computation (dereference, *i ) and an expression with a side effect (dereference and increment, *i++ ) without an intervening sequence point. Remember *i++ is evaluated as *(i++) ; you're incrementing the pointer value, not the thing being pointed to.


Given x = *i + *i++; it would be legitimate for the sub-expression i++ to be broken down into seven pieces:

  • Capture the state of the pointer for the *i++ part of the expression
  • Read that address
  • Capture the state of the pointer for the *i part of the expression
  • Read that address
  • Add the two values read
  • Store the result in X.
  • Put the pointer into an invalid state (eg for pointers larger than int , start by incrementing the bottom half, which might wrap)
  • Put the pointer into a valid state which identifies the next object (finish writing an updated pointer value)
  • Steps #1 must be first, and must precede #7, which must in turn precede #8, but the compiler may rearrange any or all of the operations #2-#6 so they occur before, after, or between #7 and #8. Nothing in the Standard would require a compiler to make any effort to ensure that all other accesses to that same pointer will occur before #7 or after #8; if a compiler does happen to put a different access between steps #7 and #8, there's no telling what the consequences of using the temporarily-invalid pointer might be.

    链接地址: http://www.djcxy.com/p/73220.html

    上一篇: 是什么让我=我++ + 1; 在C ++ 17合法吗?

    下一篇: 在同一时间修改指向的值和指针UB