compiler difference between ++a & mask; , a++ & mask; , a = (a + 1) & mask; ??

There's probably a logical explanation for this, but I'ld like to understand:

I have a variable in my code that I have to increment and then mask. I can do that in three different ways:

  1. countPer = countPer++ & B00011111;//0 -> 31 by "+ 1", 31 -> 0 by "&"
  2. countPer = ++countPer & B00011111;//0 -> 31 by "+ 1", 31 -> 0 by "&"
countPer = (countPer + 1) & B00011111;//0 -> 31 by "+ 1", 31 -> 0 by "&"

All three methods give a different result: 1) makes the code 8 bytes longer than 3), and 2) makes it 6 bytes longer than 3). So 3) seemed the most efficient!

Here are the results (code snippets) that I found in the .lss file (I'm using UECIDE, that generates it as a bonus alongside my .ino):

volatile unsigned char  countPer	= 0;	// periods counter;

countPer = countPer++ & B00011111;//0 -> 31 by "+ 1", 31 -> 0 by "&"
 146:	80 91 01 01 	lds	r24, 0x0101
 14a:	98 2f       	mov	r25, r24
 14c:	9f 71       	andi	r25, 0x1F	; 31
 14e:	90 93 01 01 	sts	0x0101, r25
 152:	8f 5f       	subi	r24, 0xFF	; 255
 154:	80 93 01 01 	sts	0x0101, r24

countPer = ++countPer & B00011111;//0 -> 31 by "+ 1", 31 -> 0 by "&"
 146:	80 91 01 01 	lds	r24, 0x0101
 14a:	8f 5f       	subi	r24, 0xFF	; 255
 14c:	80 93 01 01 	sts	0x0101, r24
 150:	80 91 01 01 	lds	r24, 0x0101
 154:	8f 71       	andi	r24, 0x1F	; 31
 156:	80 93 01 01 	sts	0x0101, r24

countPer = (countPer + 1) & B00011111;//0 -> 31 by "+ 1", 31 -> 0 by "&"
 146:	80 91 01 01 	lds	r24, 0x0101
 14a:	8f 5f       	subi	r24, 0xFF	; 255
 14c:	8f 71       	andi	r24, 0x1F	; 31
 14e:	80 93 01 01 	sts	0x0101, r24

Should I consider this a (mild) bug? Or is there a logical explanation (I'm relatively new to programming, I'm afraid...)?

Thanks for any thoughts,
Marc

The 3 lines you have posted are absolutely NOT equivalent, they have different meanings, so they obviously compile and behave differently.

Actually #1 and #2 are even UNDEFINED BEHAVIOUR in the C standard, since you are modifying the same variable more than once in a single expression (I think they're missing a sequence point).

So let's remove the double assignment and say we have the following:

int a = 5;
int b = ++a / 2;

After this: a = 6, b = 3.

int a = 5;
int b = a++ / 2;

After this: a = 6, b = 2.

int a = 5
int b = a / 2;

After this: a = 5, b = 2.

If you can't understand the differences, I think you should review the pre/post-increment operations in your C manual. If you do understand, what you should use depends on what exactly you want to do.

++a will increment a, THEN use the new value to evaluate the expression.

So, it is equivalent to:

a++ will use the existing value of a to evaluate the expression, THEN increment a.

Regards,
Ray L.

SukkoPera:
Actually #1 and #2 are even UNDEFINED BEHAVIOUR in the C standard, since you are modifying the same variable more than once in a single expression (I think they're missing a sequence point).

I don't think that's true.... There are certainly cases where use of ++ or -- can cause undefined results, but I don't think this is one of them. Sequence points come into play when the order of evaluation of operands is undefined, so different compilers can legitimately evaluate operands in different orders, creating side-effects. In this case, the entire expression MUST be evaluated before the final assignment takes place, and the result is invariant. That will ensure a correct result, regardless of order of evaluation.

Regards,
Ray L.

So let's remove the double assignment and say we have the following:
Code:
int a = 5;
int b = ++i / 2;
After this: a = 6, b = 3.

I think "i" is supposed to be "a".

Erm, of course! Fixed, thanks! :blush: