I'm writing some code for a CPU with 16-bit wide registers.
typedef unsigned int uint32;
typedef unsigned short uint16;
From a standard C perspective, unless otherwise specified,
uint16 might be any number of bits n at least 16,
uint32 might be any number of bits m at least n.
Given "a CPU with 16-bit wide registers"
- unsigned short aka uint16 is almost certainly 16-bit
- unsigned int aka uint32 likely is 16-bit or 32-bit
- likely, at least one of unsigned int or unsigned long
is 32-bit.
In (another/future) C99-conformant universe, <stdint.h> would help.
In the meantime, I suggest you add at least
#if UINT_MAX<0xFFFFFFFFul
# error "unsigned int aka uint32 is not at least 32 bit"
#endif
and/or if you accept/want depend on exact bit size and mask using cast:
#if USHRT_MAX!=0xFFFF
# error "unsigned short aka uint16 is not 16 bit"
#endif
#if UINT_MAX!=0xFFFFFFFFul
# error "unsigned int aka uint32 is not 32 bit"
#endif
#define ASSERT_S(condition) extern char assert_failure[(condition)?1:-1]
ASSERT_S((uint16)(-1)==0xFFFF); /* check cast to uint16 */
ASSERT_S((uint32)(-1)==0xFFFFFFFF); /* check cast to uint32 */
Note: the above will not generate any extra code.
int write_reg(int unit, uint32 addr, uint16 val);
int foo(int unit, unsigned int group, unsigned long portmask)
{
write_reg(unit, REG0, portmask & 0xffff); /* XXX */
....
}
On a marked line, is it necessary to cast the expression to uint16, i.e.
(uint16)(portmask & 0xffff), or this conversion will happen automatically ?
This conversion will happen automatically but it might generate a
warning for some compiler settings; the warning can be avoided with
write_reg(unit, REG0, (uint16)(portmask & 0xffff) );
but some compilers will generate better code for
write_reg(unit, REG0, (uint16)(portmask) & 0xffff );
After checking that uint16 is really 16-bit and cast to uint16
work, I suggest
write_reg(unit, REG0, (uint16)(portmask) );
Francois Grieu