The comma operator is simple - so easy that it is complicated. It has the lowest priority for all operators; its priority is even lower than assignment operators. Note that function arguments are not separated by a comma operator.
The comma operator calculates the left operand, generates a sequence point and discards the result, and then evaluates the right operand.
In the context:
x++, ++x, x += x;
is equivalent to:
x++; ++x; x += x;
except that the total value is the result of x += x; .
Given that x starts at 16, it increases to 17, then 18, and then doubles to 36. Thus, the total value is 36.
Note that due to points in the sequence, it does not fulfill the rules foul not to increment the same variable more than once between points in the sequence.
The only reason for using the comma operator is that there are contexts in which you cannot use separate instructions, but you can use commas. For instance:
for (i = 0, j = n; i < j; ++i, --j)
Instead of these commas, you cannot use semicolons.
There are two examples in this question:
int y = (x++, ++x, x+=x); int y = x++, ++x, x+=x;
The first is legal (albeit overly distorted) and initializes y to 36 (and sets x to 36).
The second is not legal and will not compile; commas are not comma operators and must be separated by different declarators, but ++x and x += x are not declarators. However, if it was changed to:
y = x++, ++x, x+=x;
then it would be legal. First member:
y = x++
which assigns a value from 16 to y and increases x to 17. The second term increases x to 18; the third term changes x to 36.