-1

I'm porting my game to Android which has around 200k lines of code and encountered a very strange bug, after 5 hours of digging I cracked it down to this line:

// background info
short m = ((dwMask << 4) | dwMask) << ASTAR_OFFSET_VIS;
short zm = (~ASTAR_MASK_DISCOVERED) | (~dwMask);
short *b = (short*)tilecache.GetDataPtr() + index;

// unexpected behavior
*b++ = (*b&zm) | m;

// works
*b = ((*b)&zm) | m; b++;

My guess is this compiler (GCC ARM) treats the ++ operator differently than all other compilers I've built this game on, which seems a little crazy, but not unbelievable. Previously the game has been built for Windows, Mac, iOS, and Windows CE and all processed the top version fine.

I think it's evaluating (*b&zm) | m then incrementing the pointer b++ then doing the assignment, because data is shifted left in my array each evaluation.

I have located numerous places in my code that use this type of syntax and changed them, but I want to make sure the problem is what I'm thinking it is, and if this is a compiler option I could switch to make it the same as the other compilers I use? In case I have other syntax like this in my code elsewhere.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
Rasterman
  • 155
  • 1
  • 13
  • 1
    Isn't that just an obscure version of the tired old `i = i++` question? – Kerrek SB Dec 06 '14 at 22:36
  • http://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points – stark Dec 06 '14 at 22:40
  • @KerrekSB: actually, it _isn't_! `i = i++` modifies `i` twice which is obviously undefined behavior. The expression in the question doesn't modify `b` twice. I think this expression has unspecified results rather than resulting in undefined behavior. – Dietmar Kühl Dec 06 '14 at 22:41
  • This is what happens when you get clever. Keep it simple, avoid edge conditions, and you won't waste hours tracking down minor oddities of compiler behavior. – Michael Kohne Dec 06 '14 at 22:42
  • 1
    @DietmarKühl: Hmmm. "If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object *or a value computation using the value of the same scalar object*, and they are not potentially concurrent (1.10), the behavior is undefined." Isn't `*b` a value computation and `b++` has a side effect? – Kerrek SB Dec 06 '14 at 22:47
  • @KerrekSB: good point. This statement seems to be more precise than what I remembered from the C++03 specification but I agree that this statement says that the result is undefined behavior. It is still different from `i = i++` as this is actually two unsequenced modifications and a value computation unsequenced with a modification. – Dietmar Kühl Dec 06 '14 at 22:53
  • @DietmarKühl: Right, it's not the same C++ question as `i = i++`, but the Stack Overflow question on that topic includes the C++11 answer. Sorry for being oblique. – Kerrek SB Dec 06 '14 at 23:27

1 Answers1

3

The order in which arguments to functions or operators (including built-in operators) are evaluated is unspecified. Some compilers will evaluate the expressions from left to right, others evaluate them from right left. For some operators, e.g., the comma, the ternary, and the logic operators the order in which the arguments are evaluated and when side-effects happen is specified: the first operand is evaluated first.

This is unrelated to operator precedence which determines in which order the operators are evaluated. It is also unspecified when side-effects happen other than that they happen at the end of a full expression or after evaluating the first argument of one of the special operators.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • Thank you, does your answer mean my problem is incrementing b AND accessing it in the same statement and the order the increment and access are performed in is undefined? So doing *b++=*s; is fine because its value doesn't depend on itself? – Rasterman Dec 07 '14 at 13:50
  • @Rasterman: yes, modifying a variable of a built-in type and using the same variable in the same expression (unless on different sides of one of the special operators) results in undefined behavior (I thought it would just be unspecified but KerrekSB clarified in a comment that it is actually undefined). – Dietmar Kühl Dec 07 '14 at 14:18