Categories
Mastering Development

Do the multiple postfix-expression(subscripting) evaluations result in UB

#include <iostream>
int main(){
   int  arr[7] = {0,1,2,3,4,3,2};
   arr[0]++[arr]++[arr]++[arr]++[arr]++[arr]++[arr] = 5;  //#1
   for(auto i = 0;i<7;i++){
       std::cout<<i<<" : "<< arr[i]<<std::endl;
   }
}

Consider the above code, Is this evaluation at #1 would result in UB? This is a example I have saw in twitter.

According to the evaluation sequence for postfix ++:
expr.post.incr#1

The value computation of the ++ expression is sequenced before the modification of the operand object.

That means, such a example would result in UB

int arr[2] = {0};
(*(arr[0]++ + arr))++

Because, the side effect caused by expression arr[0]++ and (*(arr[0]++) + arr))++ are unsequenced and applied to the same memory location.

However, for the first example, It’s difference. My argument is:
expr.sub#1

The expression E1[E2] is identical (by definition) to *((E1)+(E2)),…, The expression E1 is sequenced before the expression E2.

That means, every value computation and side effect associated with E1 are both sequenced before every value computation and side effect associated with E2.

To simplify the expression at #1, according to the grammar of expression, such a expression should conform to:
expr.ass

logical-or-expression assignment-operator initializer-clause

And expr.post#1

Where the logical-or-expression here is a postfix-expression. That is,

postfix-expression [ arr ] = 5;

Where the postfix-expression has the form postfix-expression ++, which in turn, the postfix-expression has the form postfix-expression[arr]. In simple, the left operand of assignment consists of two kinds of postfix-expressions, they alternate combination with each other.

Postfix expressions group left-to-right

So, let the subscript operation has the form E1[E2] and the postfix++ expression has the form PE++, then for the first example, it will give a following decomposition like this:

E1': arr[0]++ 
E2': arr
E1'[E2']: arr[0]++[arr]
PE'++ : E1'[E2']++

E1'': PE'++
E2'': arr
E1''[E2'']: PE'++[arr]
PE''++: E1''[E2''] ++

and so on...

That means, in order to caculate PE'++, E1'[E2'] should be calculated prior PE'++, which is identical to *((E1′)+E2′), per the rule E1' is sequenced before E2', hence the side effect caused by E1' is sequenced before value computation for E2'.
In other words, each side effect caused by postfix++ expression must be evaluated prior to that expression combined with the subsequent [arr].

So, in this way, I think such a code at #1 should have well-defined behavior rather than UB. Is there anything I misunderstand? Whether the code is UB or not? If it’s not UB, what’s the correct result the code will give?

Leave a Reply

Your email address will not be published. Required fields are marked *