1

Help me please understand the following expression:

(seen in a book)

*((int *)marks + i++) = i+1

A large number of increments and symbols dereference confusing!

Stefano Sanfilippo
  • 32,265
  • 7
  • 79
  • 80
ReDSerpenT
  • 129
  • 5

7 Answers7

5

I hope the book had this as a bad example, because the behavior of that is undefined.

(int *)marks interprets marks (whatever that may be) as a pointer to int, then we have the result of i++ added to that. This pointer is dereferenced and i+1 is assigned to the corresponding object.

This expression has no defined behavior because it reads and modifies i at two different subexpressions that are not sequenced one before the other.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • Out of curiosity: is there any guarantee about the evaluation order of left and right member? I remember the answer being no, but I could not track the exact part of the specs in which this is mentioned. – Stefano Sanfilippo Jan 27 '14 at 14:09
  • No, as I indicated there is no sequence point, so the left and right expressions could be evaluated in any order, intertwined, in parallel whatever. – Jens Gustedt Jan 27 '14 at 14:10
5

Burn the book.

The behaviour of the statement is undefined due to there being no sequence points. A far simpler case to understand is i++ = i which is also undefined.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
0

Note: As others have said, the i++ expression is undefined behavior. In g++, the i++ operation will be executed as follows:

// Pointer to some data.
void* marks = ???;
// Typecast to an integer pointer
int* marksIntPointer = (int*)marks;
// Move the position in memory. I am assuming that 'marks' is an array.
int* marksIntPointerOffset = marksIntPointer + i;
// Undefined behaviour, could take place here or before, depending on the compiler (as others have said).
i++;
// Set the value of the desired memory.
*marksIntPointerOffset = i+1;
elimirks
  • 1,452
  • 2
  • 17
  • 30
  • 2
    If it wasn't for an undefined behaviour... I mean, `i++` will be executed after `int* marksIntPointerOffset = marksIntPointer + i;`, correct. But will `i + 1` be evaluated before or after `i++`? – Stefano Sanfilippo Jan 27 '14 at 14:09
  • -1, this answer is misleading, since it presents this as a linear flow. In fact the evaluation of `i+i` in the last row can appear at any point inbetween. In that, reading of `i` may even return an invalid value, if the `i++` operation can't be done in one instruction. – Jens Gustedt Jan 27 '14 at 14:14
  • Unless g++ compiles incorrectly, it is defined behavior. Check my edit. – elimirks Jan 27 '14 at 14:23
  • Testing with the compiler is not enough. Compiler is allowed to misbehave in undefined behaviour. – user694733 Jan 27 '14 at 14:25
  • 2
    @elimirks, first for your update, this is C and not C++ :) Then testing with a compiler tells you nothing about undefined behavior. The essence of undefined behavior is that no compiler has to detect it or do anything about it. Only for "constraint violations" a compiler must give a diagnostic. – Jens Gustedt Jan 27 '14 at 14:25
  • Thanks for the information, I read up on undefined behavior regarding the incrementation operators and now understand. I updated my answer accordingly. – elimirks Jan 27 '14 at 14:39
0

The mentioned expression yields an undefined behavior.

C99 6.5 §2 states:

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.

2) Furthermore, the prior value shall be read only to determine the value to be stored.


1) Storing and modifying the value of variable within a single expression is pretty straightforward:

i = ++i;
i++ = i;
++i = 7;

as well as modifying the value of the same variable multiple times within a single expression:

j = ++i + ++i;

2) Reading only to determine the value to be stored might be a bit tricky though. This means that even the following (just like the previous examples) invoke the undefined behavior:

j = (i + 1) + i++;
a[i++] = i;  
*(ptr + i++) = i;

as well as:

*((int *)marks + i++) = i+1

You might look at: Undefined behavior and sequence points as well :)

Community
  • 1
  • 1
LihO
  • 41,190
  • 11
  • 99
  • 167
0

As others have mentioned, the behavior is undefined; by getting rid of the ++ operator, the following code would be well-defined (but still ugly as sin):

*((int *)marks + i) = i+1

Here's how it breaks down:

         marks               -- take the expression marks
  (int *)marks               -- cast it as a pointer to int
  (int *)marks + i           -- offset i integer elements from that address
*((int *)marks + i)          -- deference the result to get an array element
*((int *)marks + i) = i+1    -- assign the result of i+1 to that element

This is essentially treating marks as an array of int, and assigning the result of i+1 to the i'th element:

int *mp = (int *) marks;
mp[i] = i+1

The original expression was trying to do

mp[i++] = i+1

which invokes undefined behavior. Since the order in which i++ and i+1 are evaluated is not specified; the compiler is free to evaluate them in any order it feels like. Since i++ has a side effect (updating the value of i), this means that you will get different results based on the platform, optimization settings, even the surrounding code. The language standard explicitly leaves the behavior undefined so that the compiler isn't required to handle this code in any particular way. You will get a result, but it's not guaranteed to be consistent from compiler to compiler (or even from run to run).

John Bode
  • 119,563
  • 19
  • 122
  • 198
-2
(int *)marks

cast marks to a int pointer

+ i++

add i at marks (chaging the address pointed) and then increments i by 1

*(...) = i+1

set the VALUE of the cell pointed by our pointer to i+1 (pay attention at the fact that i as already been incremented before, so it will be greater of 2 by the start of the instruction.

I hope this is an example f how you should NOT write the code :)

Lesto
  • 2,260
  • 2
  • 19
  • 26
-2

Let's see.

*((int *)marks + i++) = i+1

-marks is cast to a pointer to int
-i is incremented by one
-the pointer (int *)marks is advanced by the value (i+1) using pointer arithmetic
-this pointer is now dereferenced, so...
-... the memory location to which it points is now written with the value of i+1