T
Tomás Ó hÉilidhe
I'll try to summarise this as best I can, as my last thread wasn't
very to-the-point:
The C Standard says the following two things:
* int is the natural integer type for the system.
* int must be at least 16-Bit.
Now the problem here is that these two criteria conflict if the
natural type for the system is in fact 8-Bit, which is the case with
many microcontrollers today.
As an example, let's take the following code:
char unsigned x, y;
...
x = y;
On my microcontroller compiler, this produces different assembler
depending on whether 'x' is an "unsigned int" or an "unsigned char".
If it's an "unsigned char", then the assembler is:
MOVF y, W /* Copy y to the accumulator */
MOVWF x /* Copy the accumulator to x */
However, if 'x' is an "unsigned int", then the assembler is:
MOVF y, W /* Copy y to the accumulator */
MOVWF x /* Copy the accumulator to x */
MOVF y+1, W /* Copy the next byte of y to the acc */
MOVWF x+1 /* Copy the acc to the next byte of x */
Now quite plainly to see, the "int" version takes twice as many
instructions in this case, and will therefore take exactly twice as
long to execute, and so will be twice as slow. In other situations,
the difference is far worse; let's take for example the following
code:
if (condition) x = y;
Depending on the type of x and y, this produces either:
MOVF y, W /* Copy y to the accumulator */
BTFSC condition /* If condition is false, skip the next
instruction */
MOVWF x /* Copy the accumulator to x */
or:
BTFSS condition /* Skip the next instruction if condition is true
*/
GOTO There
MOVF y, W /* Copy y to the accumulator */
MOVWF x /* Copy the accumulator to x */
MOVF y+1, W /* Copy the next byte of y to the acc */
MOVWF x+1 /* Copy the acc to the next byte of x */
There:
Not only does the int version consist of more instructions, but it
also involves a goto which will take up even more time. So basically
if your microcontroller is running at 8 MHz, then you may aswell
pretend it's running at 4 MHz or 2 MHz if you're going to be using int
for doing everyday arithmetic.
Now we could go down the road of discussing how C is inadequate in
terms of its accommodation of microcontrollers, but I'd rather discuss
ways of "making it right". The reason I'm so eager to bridge the gap
is that, other than the "int" situation, C is actually great for
programming an embedded system. I used it in my college project this
year to program a portable electronic Connect4 game, and it worked
great!
One way of making things right is to stop using int for arbitrarily
storing numbers, and instead use something like ufast8 (the fastest
integer type that's at least 8-Bit). In this way, neither the
microcontrollers nor the PC's suffer.
Examples of a piece of code that could be brought between PC's and
microcontrollers is something like a look-up table as follows:
ufast8 days_in_month[12] =
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
To those people out there who are enthusiastic about writing portable
code, how do you feel about using types such as ufast8 instead of int?
stdint.h is great and all, but I find the type names to be too long
winded. For instance I'd rather write "ufast8" instead of
"uint_fast8_t".
very to-the-point:
The C Standard says the following two things:
* int is the natural integer type for the system.
* int must be at least 16-Bit.
Now the problem here is that these two criteria conflict if the
natural type for the system is in fact 8-Bit, which is the case with
many microcontrollers today.
As an example, let's take the following code:
char unsigned x, y;
...
x = y;
On my microcontroller compiler, this produces different assembler
depending on whether 'x' is an "unsigned int" or an "unsigned char".
If it's an "unsigned char", then the assembler is:
MOVF y, W /* Copy y to the accumulator */
MOVWF x /* Copy the accumulator to x */
However, if 'x' is an "unsigned int", then the assembler is:
MOVF y, W /* Copy y to the accumulator */
MOVWF x /* Copy the accumulator to x */
MOVF y+1, W /* Copy the next byte of y to the acc */
MOVWF x+1 /* Copy the acc to the next byte of x */
Now quite plainly to see, the "int" version takes twice as many
instructions in this case, and will therefore take exactly twice as
long to execute, and so will be twice as slow. In other situations,
the difference is far worse; let's take for example the following
code:
if (condition) x = y;
Depending on the type of x and y, this produces either:
MOVF y, W /* Copy y to the accumulator */
BTFSC condition /* If condition is false, skip the next
instruction */
MOVWF x /* Copy the accumulator to x */
or:
BTFSS condition /* Skip the next instruction if condition is true
*/
GOTO There
MOVF y, W /* Copy y to the accumulator */
MOVWF x /* Copy the accumulator to x */
MOVF y+1, W /* Copy the next byte of y to the acc */
MOVWF x+1 /* Copy the acc to the next byte of x */
There:
Not only does the int version consist of more instructions, but it
also involves a goto which will take up even more time. So basically
if your microcontroller is running at 8 MHz, then you may aswell
pretend it's running at 4 MHz or 2 MHz if you're going to be using int
for doing everyday arithmetic.
Now we could go down the road of discussing how C is inadequate in
terms of its accommodation of microcontrollers, but I'd rather discuss
ways of "making it right". The reason I'm so eager to bridge the gap
is that, other than the "int" situation, C is actually great for
programming an embedded system. I used it in my college project this
year to program a portable electronic Connect4 game, and it worked
great!
One way of making things right is to stop using int for arbitrarily
storing numbers, and instead use something like ufast8 (the fastest
integer type that's at least 8-Bit). In this way, neither the
microcontrollers nor the PC's suffer.
Examples of a piece of code that could be brought between PC's and
microcontrollers is something like a look-up table as follows:
ufast8 days_in_month[12] =
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
To those people out there who are enthusiastic about writing portable
code, how do you feel about using types such as ufast8 instead of int?
stdint.h is great and all, but I find the type names to be too long
winded. For instance I'd rather write "ufast8" instead of
"uint_fast8_t".