conversion

M

Mark

I'm writing some code for a CPU with 16-bit wide registers.

typedef unsigned int uint32;
typedef unsigned short uint16;

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 ?

Thanks.
 
T

Tim Rentsch

Mark said:
I'm writing some code for a CPU with 16-bit wide registers.

typedef unsigned int uint32;
typedef unsigned short uint16;

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 ?

Since there is a prototype for 'write_reg()' visible at the
point of the call, the conversion will happen automatically.

That result doesn't hold though if there is no declaration
or if the declaration doesn't include the types of the
parameters, so don't forget to declare the argument types
in the function declaration.
 
J

jacob navia

Mark a écrit :
I'm writing some code for a CPU with 16-bit wide registers.

typedef unsigned int uint32;
typedef unsigned short uint16;

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 ?

Thanks.

No.
The conversion to unsigned short
should be done automatically bythe compiler when
constructing the argument list

But...


Why do you make the mask at all? Only the lower 16 bits should be used
anyway
 
F

Francois Grieu

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
 
A

Andrey Tarasevich

Mark said:
I'm writing some code for a CPU with 16-bit wide registers.

typedef unsigned int uint32;
typedef unsigned short uint16;

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 ?

Given the above declaration layout, it will indeed happen automatically.
There's no need for an explicit conversion.

However, some compilers might issue a warning in this case, telling you
that implicit truncation of `unsigned long` value to `unsigned short`
type takes place and can potentially lose data (even though you are
masking your data with `0xffff`). To suppress that warning you might
have to include that explicit conversion in your code.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top