Reputation: 3537
I have these definitions:
int data = uartBaseAddress[UART_DATA_REGISTER / 4]; // data coming from UART RX port
char message[20]; // array of 20 chars
Now when I try to do this:
message[0] = (char) data;
printf("%x", message[0]);
It prints (for example): "ffffff9c"
.
Of course I want only the last 8 bits ("9c") and I don't understand how to properly do the conversion from int
to char
.
EDIT: I mean: i have to populate the array like this:
data = 0xFFFFFF9c;
message[0] = data & 0xFF; -- it has to contain only 9c
data = 0xFFFFFFde;
message[1] = data & 0xFF; -- it has to contain only de
etc...
Upvotes: 3
Views: 9474
Reputation: 263647
The conversion is correct. It's the printf
that's the problem.
Apparently plain char
is signed on your system (it can be either signed or unsigned).
I'm going to guess that the value printed was ffffff9c
(8 digits), not ffffffff9c
(10 digits); please verify that.
The value of data
was probably -100
. Converting that value from int
to char
would yield -100
, since that value is within the range of type char
(probably -128
.. +127
).
But the %x
format specifier requires an argument of type unsigned int
, not int
. The value of message[0]
is promoted to int
when it's passed to printf
, but printf
, because of the format string, assumes that the argument is of type unsigned int
.
Strictly speaking, the behavior is undefined, but most likely printf
will simply take the int
value passed to it and treat it as if it were an unsigned int
. (int)-100
and (unsigned int)0xffffff9c
have the same representation.
There is no printf
format specifier to print a signed value in hexadecimal. If you change the format from %x
to %d
, you'll at least see the correct value.
But you should step back an decide just what you're trying to accomplish. If you want to extract the low-order 8 bits of data
, you can do so by masking it, as unwind's answer suggests. Or you can convert it to unsigned char
rather than plain char
to guarantee that you'll get an unsigned value.
An unsigned char
value is still promoted to int
when passed to printf
, so to be fully correct you should explicitly convert it to unsigned int
:
int data = ...;
unsigned char message[20]; // change to unsigned char
message[0] = data; // no cast needed, the value is implicitly converted
printf("%x", (unsigned int)message[0]);
Strictly speaking, the (unsigned int)
isn't necessary. message[0]
is an unsigned char
, so it will be converted to a non-negative int
value, and there's a special-case rule that says int
and unsigned int
arguments with the same value are interchangeable as function arguments. Still, my own preference is to use the cast because it's clearer, and because adding the cast is easier (particularly for anyone reading the code) than following the line of reasoning that says it's not necessary.
Upvotes: 6
Reputation: 400139
There's no need for message
, just mask off the bits you don't want:
printf("%x\n", data & 0xff);
To convert a 32-bit integer to a 4-element array of 8-bit numbers, do:
const uint32_t data = ...
uint8_t message[20];
for(int i = 0; i < 4; ++i)
{
message[i] = data & 0xff;
data >>= 8;
}
The above uses little-endian byte order. If data
is 0x12345678
, then message
will begin 0x78, 0x56, 0x34, 0x12
.
Upvotes: 5