7

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.

Michael Smith
  • 1,271
  • 1
  • 8
  • 31
  • Have a look at https://stackoverflow.com/questions/4968854/is-i-i-truly-a-undefined-behavior – Hong Ooi Mar 07 '18 at 01:10
  • `*it = *(++it);` yields undefined behaviour, anything can happen. – Pablo Mar 07 '18 at 01:13
  • 1
    Possible duplicate of [is i=i++ truly a undefined behavior?](https://stackoverflow.com/questions/4968854/is-i-i-truly-a-undefined-behavior) – Pablo Mar 07 '18 at 01:14
  • There's a really easy way to understand the complexities of "++": never use it. Ever. You don't need it, and it will never confuse you again. – Lee Daniel Crocker Mar 07 '18 at 01:16
  • 1
    @HongOoi @Pablo Is it? This is not `i = i++` like the examples provided in the linked question. This is assigning a value pointed to by `it` to the value in front of it, `it + 1` or `++it`. – Michael Smith Mar 07 '18 at 01:16
  • 1
    @MichaelSmith It's UB for the same reason. `++it` modifies the variable `it`, while trying to assign the result of the expression to `it`. This is why this is undefined behavior, you are trying to modify the same variable twice on a single expression. Odds are `*it = *(++it);` is the same as just doing `++it`, but who knows how the compiler is optimizing that behind the scene. By that logic the first code snippet actually modifies the array, the second doesn't. – Havenard Mar 07 '18 at 01:38
  • @LeeDanielCrocker: That is not a solution. Most programmers must work with other people’s code, often on a regular basis. Not using a language feature yourself will not prevent you from encountering it. And a strategy of cultivating ignorance is not a recipe for success. – Eric Postpischil Mar 07 '18 at 03:42

2 Answers2

4

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.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
2

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.

melpomene
  • 84,125
  • 8
  • 85
  • 148
  • 1
    C99? You can find links to newer versions of the standard [here](https://stackoverflow.com/questions/81656/where-do-i-find-the-current-c-or-c-standard-documents). – Eric Postpischil Mar 07 '18 at 01:29