[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [avr-gcc-list] uint8_t assembled as uint16_t in some cases?
From: |
E. Weddington |
Subject: |
Re: [avr-gcc-list] uint8_t assembled as uint16_t in some cases? |
Date: |
Tue, 09 Dec 2003 09:41:52 -0700 |
On 9 Dec 2003 at 11:22, Robert Baruch wrote:
> Hi all,
>
> I have some test code which shows that there's a case where gcc
> needlessly converts a uint8_t into a uint16_t. Here's the code:
>
<snip>
> So why the extra instruction at 0x56? It seems that although flags was
> declared to be uint8_t, the compiler is treating it as a uint16_t. More, if
> I change the if-statement from (flags & 0x02) to (flags == 0x02), the extra
> instruction goes away. So it seems to have something to do with the bit-wise
> operators.
>
> Anyone have any idea? Is it a genuine bug? Is there somewhere in the
> source I should be looking for this? Any workaround?
This is not a bug. The C Standard states that bitwise operators can promote
a char to an int. GCC adheres to the Standard pretty closely, even though
some things in the Standard are not amenable to embedded systems. Remember
that GCC is used on a variety of computer platforms as well. This issue is
also noted in the avr-libc FAQ (#20), which is in the avr-libc user manual.
Did you look there?
The workaround is to typecast the operation. For example if you are
clearing bits, you could do something like:
(uint8_t)PORTB &= (uint8_t)~mask;
Note that in the specific example of clearing bits, be sure to place the
typecast *before* the bitwise NOT operator, as that operator could promote
to int.
If you feel that liberally sprinkling typecasts would look ugly, you can
always create macros, such as:
#define bit_clear_byte(var, mask) ((uint8_t)(var) &= (uint8_t)~(mask))
bit_clear_byte(PORTB, 0x01);
You can also define macros for 16-bit sizes:
#define bit_clear_word(var, mask) ((uint16_t)(var) &= (uint16_t)~(mask))
And of course macros for setting bits, toggling bits, etc.
HTH
Eric