Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: Union vs Bitwise operators

I have two char's and I want to "stitch" them bitwise together.
For example:

char c1 = 11; // 0000 1011
char c2 = 5;  // 0000 0101
short int si = stitch(c1, c2); // 0000 1011 0000 0101

So, what I first tried was with bitwise operators:

short int stitch(char c1, char c2)
{
    return (c1 << 8) | c2;
}

But this doesn't work: I'm getting a short equals to c2... (1) Why?
(But: c1 and c2 are negative numbers in my real app... maybe this is a part of the problem?)

So, my second solution was to use a union:

union stUnion
{
    struct
    {
         char c1;
         char c2;
    }
    short int si;
}

short int stitch(char c1, char c2)
{
    stUnion u;
    u.c1 = c1;
    u.c2 = c2;
    return u.si;
}

This works like I want... I think

(2) What is the best/fastest way?

Thanks!

like image 742
Martijn Courteaux Avatar asked Dec 17 '22 22:12

Martijn Courteaux


2 Answers

The union method is implementation-defined at best (in practice, it will pretty reliably work but the format of si depends on the endianness of the platform).

The problem with the bitwise way is, as you suspect, the negative numbers. A negative number is represented by a chain of leading 1's. So -5 for example is

1111 1011

If you cast this to int or even unsigned int, it becomes

1111 1111 1111 … 1111 1011

and all those 1's will drown out the left-shifted data when OR is applied.

To solve the problem, cast the chars to unsigned char and then to int (to prevent overflow, or even the appearance of the possibility of overflow) before shifting:

short int stitch(char c1, char c2)
{
    return ( (int) (unsigned char) c1 << 8) | (unsigned char) c2;
}

or, if you are free to change the types of the arguments and you can include <cstdint>,

uint16_t stitch( uint8_t c1, uint8_t c2)
{
    return ( (int) c1 << 8 ) | c2;
}
like image 173
Potatoswatter Avatar answered Dec 24 '22 02:12

Potatoswatter


$5.8/1 states- "The operands shall be of integral or enumeration type and integral promotions are performed. The type of the result is that of the promoted left operand. The behavior is undefined if the right operand is negative, or reater than or equal to the length in bits of the promoted left operand."

So try to typecast c1 to unsigned int and then bitwise OR with C2. Also return the output as unsigned int. chars are promoted to int but we want to be 'unsigned int'

like image 40
Chubsdad Avatar answered Dec 24 '22 01:12

Chubsdad