Bobface
Bobface

Reputation: 2952

Merge char* arrays to uint16_t

I'm trying to merge a char*-array into a uint16_t. This is my code so far:

char* arr = new char[2]{0};
arr[0] = 0x0; // Binary: 00000000
arr[1] = 0xBE; // Binary: 10111110

uint16_t merged = (arr[0] << 8) + arr[1]; 
cout << merged << " As Bitset: " << bitset<16>(merged) << endl; 

I was expecting merged to be 0xBE, or in binary 00000000 10111110.

But the output of the application is:

65470 As Bitset: 1111111110111110

In the following descriptions I'm reading bits from left to right.

So arr[1] is at the right position, which is the last 8 bits. The first 8 bits however are set to 1, which they should not be.

Also, if I change the values to

arr[0] = 0x1; // Binary: 00000001
arr[1] = 0xBE; // Binary: 10111110

The output is:

0000000010111110

Again, arr[1] is at the right position. But now the first 8 bits are 0, whereas the last on of the first 8 should be 1.

Basically what I wan't to do is append arr[1] to arr[0] and interpret the new number as whole.

Upvotes: 0

Views: 285

Answers (2)

AlexD
AlexD

Reputation: 32576

Perhaps char is signed type in your case, and you are left-shifting 0xBE vhich is interpreted as signed negative value (-66 in a likely case of two's complement).

It is undefined behavior according to the standard. In practice it is often results in extending the sign bit, hence leading ones.

3.9.1 Fundamental types
....

It is implementationdefined whether a char object can hold negative values.


5.8 Shift operators
....

The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are zero-filled. If E1 has an unsigned type, the value of the result is E1 × 2E2, reduced modulo one more than the maximum value representable in the result type. Otherwise, if E1 has a signed type and non-negative value, and E1×2E2 is representable in the corresponding unsigned type of the result type, then that value, converted to the result type, is the resulting value; otherwise, the behavior is undefined.

Upvotes: 1

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385144

You need to assign to the wider type before shifting, otherwise you're shifting away your high bits before they ever even hit the only variable here that's big enough to hold them.

uint16_t merged = arr[0];
merged <<= 8;
merged += arr[1];

Or, arguably:

const uint16_t merged = ((uint16_t)arr[0] << 8) + arr[1];

You also may want to consider converting through unsigned char first to avoid oddities with the high bit set. Try out a few different values in your unit test suite and see what happens.

Well, your program has undefined behaviour from this out-of-range shift, so who knows what might happen!

Upvotes: 1

Related Questions