Michael Smith
Michael Smith

Reputation: 1331

Why is ptr + 1 different from ++ptr in this scenario?

I originally had the following code where it is a void**:

while (it != end)
{
    *it = *(it + 1);
    it++;
}

I decided to change it + 1; it++; to ++it; because I was calculating the same value twice.

while (it != end)
{
    *it = *(++it);
}

However, after doing so, my program no longer functions the same way.

Edit: I would like to note that this is not i = i++;, but rather assigning the value pointed to by it to the value in front of it.

Upvotes: 7

Views: 153

Answers (2)

Eric Postpischil
Eric Postpischil

Reputation: 222660

In *it = *(++it);, the compiler might evaluate it for the purposes of preparing the reference *it and, after that, perform the side effect of incrementing it for ++it. Or it might do the side effect first and then evaluate it for the *it. The C standard does not say in which order these must occur. The assignment itself, storing a value in *it, must be later, but that is something else. The compiler can work on parts of the left side and parts of the right side in any order it wants.

You are not allowed both modify an object (++it) and use it (in *it) without a determined order between them. Doing so results in undefined behavior. This is per C 2011 [N1570] 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.

Incrementing it in ++it is a side effect, and using it in *it is a value computation using the value of it, which is a scalar object. Therefore, the behavior is undefined.

Upvotes: 4

melpomene
melpomene

Reputation: 85767

C99, 6.5 Expressions:

  1. Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored.

(Emphasis mine.)

In

*it = *(++it);

We read twice and store once. *it on the left side reads from it; ++it on the right side reads from and stores to it. There are no sequences points here.

This expression has undefined behavior because the read on the left side is not used to determine the value to be stored.

*it = *(it + 1); is allowed because it is not modified here (there are no stores), so you can have as many reads as you want.

Upvotes: 2

Related Questions