HBv6
HBv6

Reputation: 3537

Convert int (32 bits) to char (8 bits)

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

Answers (2)

Keith Thompson
Keith Thompson

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

unwind
unwind

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

Related Questions