Chandrapal Singh Jhala
Chandrapal Singh Jhala

Reputation: 245

Make a Integer from 6 bytes or more using C++

I am new in C++ programming. I am trying to implement a code through which I can make a single integer value from 6 or more individual bytes.

I have Implemented same for 4 bytes and it's working

My Code for 4 bytes:

char *command = "\x42\xa0\x82\xa1\x21\x22";
__int64 value;
value = (__int64)(((unsigned char)command[2] << 24) + ((unsigned char)command[3] << 16) + ((unsigned char)command[4] << 8) + (unsigned char)command[5]);
printf("%x  %x  %x  %x  %x",command[2], command[3], command[4], command[5], value);

Using this Code the value of value is 82a12122 but when I try to do for 6 byte then the result was is wrong.

Code for 6 Bytes:

char *command = "\x42\xa0\x82\xa1\x21\x22";
__int64 value;
value = (__int64)(((unsigned char)command[0] << 40) + ((unsigned char)command[1] << 32) + ((unsigned char)command[2] << 24) + ((unsigned char)command[3] << 16) + ((unsigned char)command[4] << 8) + (unsigned char)command[5]);
printf("%x  %x  %x  %x  %x  %x  %x", command[0], command[1], command[2], command[3], command[4], command[5], value);

The output value of value is 82a163c2 which is wrong, I need 42a082a12122. So can anyone tell me how to get the expected output and what is wrong with the 6 Byte Code.

Thanks in Advance.

Upvotes: 2

Views: 1649

Answers (2)

SHR
SHR

Reputation: 8313

Your shift overflows bytes, and you are not printing the integers correctly.

This code is working: (Take note of the print format and how the shifts are done in uint64_t)

#include <stdio.h>
#include <cstdint>

int main()
{
    const unsigned char *command = (const unsigned char *)"\x42\xa0\x82\xa1\x21\x22";
    uint64_t value=0;
    for (int i=0; i<6; i++)
    {
        value <<= 8;
        value += command[i];
    }
    printf("%x  %x  %x  %x  %x  %x  %llx",
             command[0], command[1], command[2], command[3], command[4], command[5], value);
}

Upvotes: 2

Max Langhof
Max Langhof

Reputation: 23681

Just cast each byte to a sufficiently large unsigned type before shifting. Even after integral promotions (to unsigned int), the type is not large enough to shift by more than 32 bytes (in the usual case, which seems to apply to you).

See here for demonstration: https://godbolt.org/g/x855XH

unsigned long long large_ok(char x)
{
    return ((unsigned long long)x) << 63;
}

unsigned long long large_incorrect(char x)
{
    return ((unsigned long long)x) << 64;
}


unsigned long long still_ok(char x)
{
    return ((unsigned char)x) << 31;
}

unsigned long long incorrect(char x)
{
    return ((unsigned char)x) << 32;
}

In simpler terms:

The shift operators promote their operands to int/unsigned int automatically. This is why your four byte version works: unsigned int is large enough for all your shifts. However, (in your implementation, as in most common ones) it can only hold 32 bits, and the compiler will not automatically choose a 64 bit type if you shift by more than 32 bits (that would be impossible for the compiler to know).

If you use large enough integral types for the shift operands, the shift will have the larger type as the result and the shifts will do what you expect.

If you turn on warnings, your compiler will probably also complain to you that you are shifting by more bits than the type has and thus always getting zero (see demonstration).

(The bit counts mentioned are of course implementation defined.)


A final note: Types beginning with double underscores (__) or underscore + capital letter are reserved for the implementation - using them is not technically "safe". Modern C++ provides you with types such as uint64_t that should have the stated number of bits - use those instead.

Upvotes: 5

Related Questions