I'm not very experienced in the world of C programming, I just worked with arduino before, and I decided to get my feet more wet by doing a project on an ATtiny13 without using the Arduino IDE, only avr-gcc via cli. Since Flash storage is at a premium, I am exploring various techniques to reduce code size. In my journey I came across multiplications and divisions, and I just became aware of the existance of libgcc with its various arithmetic routines.
So I have this small test program:
unsigned char x = 200;
void main() {
x = x*2/3;
}
If I look at the map file that is generated, I see that the compiler is adding both __udivmodhi4 and __divmodhi4 to do this calculation, of which the signed division routine __divmodhi4 seems unnecessary. However, if use a short instead of a char, as such:
unsigned short x = 200;
void main() {
x = x*2/3;
}
This time I see only __udivmodhi4 being added in the map file, which is what I would expect. I also tried with uint8_t from inttypes.h and in that case it is adding back the signed division routine.
Could anyone please explain what is going on here? In all the above-mentioned cases, I would have expected the compiler to only add the unsigned division routine. Thanks!
Apparently in the C environment you are using,
intis 16 bits. Then, whenxis anunsigned char, in the expressionx*2/3:xis promoted to anint, as part of the usual arithmetic conversions applied for the operands ofx*2.x*2, both operands have typeint, so no further promotions or conversions are needed, and the multiplication is performed withintarithmetic./areint, so the division is performed withintarithmetic.When
xis anunsigned short:unsigned shortis the same width asunsigned int, soxis not eligible for promotion toint(promotion can only be to a type that can represent all values of the source type). It is promoted tounsigned int(which is the same width asunsigned shortbut is different for purposes of applying rules about types).x*2,xis anunsigned intand2is anint, so the usual arithmetic conversions convert2to anunsigned int, and the multiplication is performed usingunsigned intarithmetic.3is converted to anunsigned int, and the division is performed usingunsigned intarithmetic.To keep the arithmetic unsigned when
xis anunsigned char, you can use any of the following expressions, among other options:(unsigned int) x * 2 / 3.x * 2u / 3.x * 2u / 3u.