Signed char conversion
-
Hi
This code gives 'c' a value of 8
@
signed char c = 127;
c = (c + 4) / 16;
@But this code gives -127
@
signed char c = 127;
c = (c + 4);
c = c / 16;
@This code gives also 8
@
signed char c = 127;
c = (c + 4) / (signed char)16;
@This code gives also 8
@
signed char c = 127;
signed char x = 4;
signed char y = 16;c = (c + x) / y;
@Could someone please explain why this is so
Thanks
-
Hi,
each compiler optimizes written code in order to reduce single CPU operations.
Probably if you do a single calculation (example 1, 3 e 4) compiler makes optimization and avoid overflow problem identified in case 2.However the correct result should be -8 because your code generates an overflow.
Regards
-
The correct result would not be -8 for example 2,
c = 127; // 127
c += 4; // 131 --> overflow = -125
c /= 16; // -7How the compiler caches temporaries in between, you never know.
it might be in example 1, that the temp value is stored as int as this is the prefered size on a 32 bit processor.In your example 2, you do not work with temporaries but store the result always in the signed int. so You get the overflow problem.
This was the test code in the debugger:
@
signed char c = 127;
c += 4;
c /= 16;
@ -
You need to remember that literals like 4 or 16 are signed integers. This is given by the standard.
@
4 // int
4u // unsigned int
4l // long
4ul // unsigned long
...
@
So:
@
(c + 4) // c is signed char, 4 is signed integer so a widening conversion is done
((int)c + 4) // this is equivalentc = (c + 4) // c is signed char, (c + 4) is signed integer, narrowing result to fit
c = (signed char)(c + 4) //this is equivalent(c + 4) / 16 // (c + 4) is signed integer, 16 is signed integer, no conversion
c = (c + 4) / 16 // (c + 4) / 16 is signed integer, c is signed char, narrowing
c = (signed char)((c + 4) / 16) // this is equivalent
@
...and so on.Reasoning the code like this you will see that your narrowing conversions occur in different places, rendering different results.
As a side note:
@//those are equivalent
(c + 4) / (signed char)16
((int)c + 4) / (int)(signed char)16
@
so the explicit cast to signed char is pointless as it will be cast back again.