A strange occurence..

I’m a student at VCU and near the shipping deadline I went out to a school in the Richmond area that my friend mentors to help them with their programming issues. Apparently the compiler is as wonderful as last year… and here’s a solution for a problem they had…

The original code went something to the tune of:


if(calib) {
  offset01 = p1_y - 128;
  calib=0;
}
if(p1_y - offset01 > 254)
  pwm01 = 254;
else if(p1_y - offset01 < 0)
  pwm01 = 0;
else
  pwm01 = p1_y - offset01;

It would seem the compiler has issues with signed and unsigned variables and doing the math ‘right’ without you being very explicit. A bit of casting is all you need…

This should be the fix:


if(calib) {
  offset01 = p1_y - 128;
  calib=0;
}
if( ((signed int) p1_y) - offset01 > 254)
  pwm01 = 254;
else if( ((signed int) p1_y) - offset01 < 0)
  pwm01 = 0;
else
  pwm01 = ((signed int) p1_y) - offset01;

That programmer fell victim to a deliberate feature of the compiler.

Rather than do calculations at the ANSI specified int size, the PIC compiler deliberately tries to keep the sizes used in calculations as small as possible to save valuable space. It will do calculations at the largest type used in the calculation. If they are all char then the calculations will be done in char and the program will suffer from any overflows that might occur during the intermediate calculations. You can override the default and force the compiler to do promote all calculations to at least integer.

See section 2.7.1 of the MPLAB C18 C Compiler User’s Guide,

http://ww1.microchip.com/downloads/en/DeviceDoc/C18_UG__51288e.pdf

[font=Times New Roman]“2.7 ISO DIVERGENCES[/font]

[font=Times New Roman]2.7.1 Integer Promotions[/font]

[font=Times New Roman]ISO mandates that all arithmetic be performed at [/font]int [font=Times New Roman]precision or greater. By default,[/font]

[font=Times New Roman]MPLAB C18 will perform arithmetic at the size of the largest operand, even if both[/font]

[font=Times New Roman]operands are smaller than an [/font]int[font=Times New Roman]. The ISO mandated behavior can be instated via the[/font]

-Oi [font=Times New Roman]command-line option.[/font]

[font=Times New Roman]For example:[/font]

unsigned char a, b;

unsigned i;

a = b = 0x80;

i = a + b; /* ISO requires that i == 0x100, but in C18 i == 0 */

[font=Times New Roman]Note that this divergence also applies to constant literals. The chosen type for constant[/font]

[font=Times New Roman]literals is the first one from the appropriate group that can represent the value of the[/font]

[font=Times New Roman]constant without overflow.”[/font]