## C programming - how to split int(16 bits) to 2 char(8bit)

11 posts / 0 new
Author
Message

I have unsigned int(16 bits) variable and 2 char(8 bit) variables. Char1 is byte1 of int variable and char2 is byte2 of int variable.
How can I split int to 2 chars, and vice versa - how can I make int from 2 chars.
I am using ICC AVR.

unsigned short MyShort;
unsigned char Char1; // lower byte
unsigned char Char2; // upper byte

// Split short into two char

Char1 = MyShort & 0xFF;
Char2 = MyShort >> 8;

// merge two char into short

MyShort = (Char2 << 8) | Char1;

This sounds like a union ...

```typedef union {
short    int_var;
char[2]  ch1ch2;
} COMBO;

COMBO   var1;

var1.int_var = 35;        // set int value to something
var1.ch1ch2[0] = 5;      // set first byte to something
var1.ch1ch2[1] = 9;      // set second byte to something
```

Dean 94TT
"Life is just one damn thing after another" Elbert Hubbard (1856 - 1915)

GedasL wrote:
I have unsigned int(16 bits) variable and 2 char(8 bit) variables. Char1 is byte1 of int variable and char2 is byte2 of int variable.
How can I split int to 2 chars, and vice versa - how can I make int from 2 chars.
I am using ICC AVR.

A UNION is the most elegant solution and designed to perform just this task.

```union u_type            //Setup a Union
{
unsigned int IntVar;
unsigned char Bytes[2];
}
temp;                    //Assign a var name to the Union

void main(void)
{
temp.IntVar=65535;          //Assign a value to the Int var of the Union
HighByte=temp.Bytes[1];  //Get the High Byte (255)
LowByte=temp.Bytes[0];   //Get the Low Byte (255)
}

```

//Sy

While the union solution will work just fine (I won't quite agree with Sy about it being "designed to perform just this task" :) ), the purists could argue that it is not portable based on endianess (big-endian [Moto], little-endian[Intel], referring to the byte order of multiple-byte binary numbers in memory storage).

So the totally-portable C solution is presented as a combination of a right-shift 8 bits for the high byte (which preserves the sign if you are careful), and a mask for the low byte. This usually takes more code & cycles than the union but, as mentioned, it is more portable across different architectures.

Another efficient way, non-portable and dipping into the bowels of the power of C (a sharp knife cuts both ways) is to use a cast on the address of the multi-bit integer into a series of char (8-bit) pointers. Example:

```unsigned char low_byte;
unsigned char high_byte;
unsigned int the_value;
...
the_value = 1234;
low_byte = * ((unsigned char *)&the_value);
high_byte = * ((unsigned char *)((&the_value)+1));
```

or a char-sized pointer could be used the same way. [I'd probably use the pointer method for repetitive uses within an app and/or many-byte variables.]

```unsigned char low_byte;
unsigned char high_byte;
unsigned int the_value;
unsigned char *the_ptr;
...
the_value = 1234;
the_ptr = * ((unsigned char *)&the_value);
low_byte = *the_ptr;
the_ptr++;
high_byte = *the_ptr;
```

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

theusch wrote:
While the union solution will work just fine (I won't quite agree with Sy about it being "designed to perform just this task" :) ), the purists could argue that it is not portable based on endianess (big-endian [Moto], little-endian[Intel], referring to the byte order of multiple-byte binary numbers in memory storage).
Lee

I agree with Lee. Unions are not very portable. The size of int is compilier (processor) dependent. I've recently used a compiler where the size of char was 32-bits (TI Code Composer for the TMS320C30).

Also, if I remember the ANSI C standard (I don't have a copy at home), union implementation is compilier dependent - the storage areas don't have to overlap. That said, I've never seen a compilier where this was the case.

Don

the bset way:

it only compile in ONe line asm code !

```#define LowB(x) (*((unsigned char*)  &(##x)+1))
#define HighB(x) (*((unsigned char*) &(##x)+0))
```

for ex for low byte use LowB(x)

maziar wrote:
the bset way:

it only compile in ONe line asm code !

```#define LowB(x) (*((unsigned char*)  &(##x)+1))
#define HighB(x) (*((unsigned char*) &(##x)+0))
```

for ex for low byte use LowB(x)

Here we go with the endian problem again.

The AVR register pairs are laid out little-endian (low byte first). The CodeVision C compiler, and AFAIK ImageCraft, gcc, & IAR also use little-endian. With any of those compilers masiar's macros are backwards.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

i am one old 8015 keil user (i am newbie in avr)

i f you think this change +1 to 0
& 0 to +1 ..

if this is true old avr c programmer reply this :

keil & IAr have diffrent byte order in int ?

If you ONLY access multi-byte items with your own macros, you can use whatever byte order you choose as long as you are consistent with each item.

Try a simple experiment with your '8051 (or other) code:

```unsigned int a;
unsigned int b;
unsigned int c;

a = 1;
b = 2;
c = a + b;
```

and examine the code produced by the compiler. The simple experiment should pretty much answer the question, as the compiler is in all probability consistent in all multi-byte operations. See if the '3' ends up in the lower RAM address or the higher.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.