'Convert four bytes to Integer using C++

I am trying to convert 4 bytes to an integer using C++.

This is my code:

int buffToInteger(char * buffer)
{
    int a = (int)(buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]);
    return a;
}

The code above works in almost all cases, for example: When my buffer is: "[\x00, \x00, \x40, \x00]" the code will return 16384 as expected.

But when the buffer is filled with: "[\x00, \x00, \x3e, \xe3]", the code won't work as expected and will return "ffffffe1".

Does anyone know why this happens?

c++


Solution 1:[1]

Your buffer contains signed characters. So, actually, buffer[0] == -29, which upon conversion to int gets sign-extended to 0xffffffe3, and in turn (0x3e << 8) | 0xffffffe3 == 0xffffffe3.

You need ensure your individual buffer bytes are interpreted unsigned, either by declaring buffer as unsigned char *, or by explicitly casting:

int a = int((unsigned char)(buffer[0]) << 24 |
            (unsigned char)(buffer[1]) << 16 |
            (unsigned char)(buffer[2]) << 8 |
            (unsigned char)(buffer[3]));

Solution 2:[2]

In the expression buffer[0] << 24 the value 24 is an int, so buffer[0] will also be converted to an int before the shift is performed.

On your system a char is apparently signed, and will then be sign extended when converted to int.

Solution 3:[3]

There's a implict promotion to a signed int in your shifts. That's because char is (apparently) signed on your platform (the common thing) and << promotes to integers implicitly. In fact none of this would work otherwise because << 8 (and higher) would scrub all your bits!

If you're stuck with using a buffer of signed chars this will give you what you want:

#include <iostream>
#include <iomanip>

int buffToInteger(char * buffer)
{
    int a = static_cast<int>(static_cast<unsigned char>(buffer[0]) << 24 |
        static_cast<unsigned char>(buffer[1]) << 16 | 
        static_cast<unsigned char>(buffer[2]) << 8 | 
        static_cast<unsigned char>(buffer[3]));
    return a;
}

int main(void) {
    char buff[4]={0x0,0x0,0x3e,static_cast<char>(0xe3)};
    int a=buffToInteger(buff);

    std::cout<<std::hex<<a<<std::endl;

    // your code goes here
    return 0;
}

Be careful about bit shifting on signed values. Promotions don't just add bytes but may convert values.

For example a gotcha here is that you can't use static_cast<unsigned int>(buffer[1]) (etc.) directly because that converts the signed char value to a signed int and then reinterprets that value as an unsigned.

If anyone asks me all implicit numeric conversions are bad. No program should have so many that they would become a chore. It's a softness in the C++ inherited from C that causes all sorts of problems that far exceed their value. It's even worse in C++ because they make the already confusing overloading rules even more confusing.

Solution 4:[4]

I think this could be also done with use of memcpy:

int buffToInteger(char* buffer)
{
    int a;
    memcpy( &a, buffer, sizeof( int ) );
    return a;
}

This is much faster than the example mentioned in the original post, because it just treats all bytes "as is" and there is no need to do any operations such as bit shift etc. It also doesn't cause any signed-unsigned issues.

Solution 5:[5]

char buffer[4];
int a;
a = *(int*)&buffer;

This takes a buffer reference, type casts it to an int reference and then dereferences it.

Solution 6:[6]

int buffToInteger(char * buffer)
{
  return *reinterpret_cast<int*>(buffer);
}

This conversion is simple and fast. We only tell compiler to treat a byte array in a memory as a single integer

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 mlegge
Solution 2 Bo Persson
Solution 3 mindriot
Solution 4 Tomasz Kowalczyk
Solution 5
Solution 6