7

I was under the impression that postincrement(OR preincrement) can be done only on right Hand side of equal(=). But I am able to compile below piece of code. Can you help me in understanding this specific code especially below line. source : http://www.ibm.com/developerworks/library/pa-dalign/

*data8++ = -*data8;


void Munge8( void *data, uint32_t size ) {
    uint8_t *data8 = (uint8_t*) data;
    uint8_t *data8End = data8 + size;

    while( data8 != data8End ) {
        *data8++ = -*data8;
    }
}
kumar
  • 2,530
  • 6
  • 33
  • 57
  • Assign `-*data8` to `*data8` then increment `data8` - effectively negating the `size` bytes at `data` – Erik Jun 18 '12 at 18:24

5 Answers5

7

So, I'm fairly sure that this is undefined behavior. There is no sequence point other than the final semicolon in:

    *data8++ = -*data8;

If data8 is equal to 0x20, is this equal to:

    *(0x20) = -*(0x20);

or

    *(0x20) = -*(0x24);

Because there is no way to make this decision, (because you've edited a variable while reading it twice, with no interleaving sequence point), this is undefined behavior.


We can talk about what the following piece of code does though. Which is likely what is intended by the above code.

while( data8 != data8End ) {
    *data8 = -*data8;
    data8++;
}

What you're doing here is hopefully more straightforward. You're taking your input array, and looking at it so it's a series of 8 bit numbers. Then, in-place, you negate each one.

Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
  • I think you are confusing "variables" here. Pointer's value and value stored at the address pointer by it are two different things. Nobody in this case have edited a variable while reading it twice. The value at address pointer by "data8" is read once on the RHS. It is written back once. Pointer is changed once on the LHS. –  Jun 18 '12 at 18:45
  • 2
    @JohnBode: Correct. `data8` is being incremented. However, we read `data8` twice in this expression. Once on the LHS, and once on the RHS. Does the read of the RHS happen before or after the increment of the pointer? I argue that it is unknown. – Bill Lynch Jun 18 '12 at 19:03
  • @sharth: Enlightenment dawns. Now I see the problem. – John Bode Jun 18 '12 at 19:45
4

Your impression is wrong, I guess. You can definitely do things like:

*a++ = *b++;

In fact, that's often how strcpy is implemented. You can even have the post- or pre-increments without an = at all:

a++;
Carl Norum
  • 219,201
  • 40
  • 422
  • 469
  • Wait, so I was in agreement with your original post. How is this not undefined behavior? – Bill Lynch Jun 18 '12 at 18:30
  • strcpy is not implemented like that though. You look for the end of string in bit patterns of larger chunks of data first, then copy data in larger chunks (usually 64 bit). –  Jun 18 '12 at 18:31
  • @sharth: How is it undefined though? I am not a standard junkie, but RHS must be evaluated first and then LHS. Thus there should be no problems. –  Jun 18 '12 at 18:33
  • 2
    @VladLazarenko: Why must the RHS be evaluated before the LHS? I see no reason that the two can't be evaluated interleaved, or in the opposite order. – Bill Lynch Jun 18 '12 at 18:34
  • @sharth - I went back and re-read it. "Between two sequence points, an object is modified more than once, or is modified and the prior value is read other than to determine the value to be stored (6.5)." The value is only being read to determine the value to be stored in this case, right? At first glance I would have said it's UD, but this reading confuses me. What's your take? – Carl Norum Jun 18 '12 at 18:37
  • @CarlNorum: Right. That allows you to do `x++;`, not this. – Bill Lynch Jun 18 '12 at 18:40
  • To put it simple, post increment means - increment the value after using it. In this case "using" means writing at the address pointer by the `data8`. In order to write there, you must actually read it first. If on RHS you had multiple increments etc - that would have been UD. –  Jun 18 '12 at 18:41
2

++ is applied to the pointer, not to the value pointed by data8.

*data8++ = -*data8;

is equivalent to:

*data8 = -*data8;
data8++;

EDIT:
After reading the C99 standard 6.5 and Annex C, it's clear = is not a sequence point. Standard mentions only &&, ||, , and ?.

Since, data8 is modified on both sides of = which no sequence point and standard doesn't mandate whether RHS should be evaluated first Or LHS should be evaluated first, I am convinced this is Undefined Behaviour.

Any good reason why assignment operator isn't a sequence point?

This above post discusses = being not a sequence point and is quite related here.

Community
  • 1
  • 1
P.P
  • 117,907
  • 20
  • 175
  • 238
  • `data8` is not modified on both sides of the assignment operator, rather it's modified on the LHS, but it's read twice with no sequence point determining how the reads are sequenced against the write. – Jason Jun 18 '12 at 19:27
  • @Jason you are right. `=` not being a sequence point is the key here. – P.P Jun 18 '12 at 19:30
1

There's no reason why post-increment cannot be done on the left-hand side of the assignment operator. A post-increment operator simply returns a temporary copy of the object in its previous state, and that temporary object (in this case a pointer) can have operations performed on it.

Now, in the case of:

*data8++ = -*data8;

because of operator ordering, the data8 pointer will first be post-incremented, returning a copy of the previous pointer value. That previous pointer value will then be dereferenced and assigned the results of the expression on the right-hand side of the assignment operator.

Edit: As others have pointed out, you're modifying the contents of data8 by reading more than once while writing to that memory location without a sequence point, so this is undefined behavior.

Jason
  • 31,834
  • 7
  • 59
  • 78
  • How is this undefined? It's like claiming `x = -x` is undefined. – John Bode Jun 18 '12 at 19:43
  • You are modifying the contents of `data8` (i.e. the pointer value itself) and then reading it back in two different locations without a sequence point. As others have pointed out, you will get two different results if the LHS or the RHS are evaluated first ... thus "undefined behavior" since the C-standard does not define which side must be evaluated first ... for instance, the evaluations of the LHS and RHS could be interleaved! In your example, there is a clear evaluation order since the LHS is not reading the value of `x`, it's just writing to it. So there is only a single read/write. – Jason Jun 18 '12 at 19:56
  • Yeah. I'll claim lack of sleep as an excuse. – John Bode Jun 18 '12 at 20:59
0

I think that

*data8++ = -*data8;

is equivalent to

*data8 = - *(data8 + 1);

data8 = data8 +1

Pontios
  • 2,377
  • 27
  • 32