zotty
zotty

Reputation: 817

Conversion of long long to byte array and back in c++

I've written a test to try and figure out how conversion between char[] arrays and long long can work. Partially for my own understanding, I'm trying to figure out the bitwise method of doing so.

Conceptually, for a long long to a char[], the below feels right. I'm shifting left, then AND-ing to limit to the right:

for (int i = 0; i < BUFFER_SIZE; i++)
{
    buffer[i] = ((value >> (8 * i)) & 0XFF);
}

To convert back, shift left and sum over the buffer:

long long recoveredValue = 0;
for (int i = 0; i < BUFFER_SIZE; i++)
{
    auto byteVal = ((buffer[i]) << (8 * i));
    recoveredValue = recoveredValue + byteVal;
}

Below is my whole test program. It seems as though when I'm filling the doing the first step above (in IntToByteArray) the value of buffer[0] is repeated at `buffer[32]'. I know there's a problem here, but I can't figure it out.

Note that for my application, I have a BUFFER_SIZE of 63, and my long long will be limited to below 2^63. Also, if I restrict BUFFER_SIZE to below 32, it works. I'm missing a subtlty regarding the 64 bit int aren't I? But where, & how?

// Test_BitConversion.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <cmath>


#define BUFFER_SIZE 64
unsigned char buffer[BUFFER_SIZE] = { 0 };  // This is the buffer I have available

// useful alternative method for checking conversion 
// can't use in production, because I'm moving between C++ & C#
union byteunion 
{
    long long value;
    unsigned char arr[BUFFER_SIZE];
};


// Convert long long to byte array
void IntToByteArray(long long value)
{
    for (int i = 0; i < BUFFER_SIZE; i++)
    {
        buffer[i] = ((value >> (8 * i)) & 0XFF);
    }
}

// Convert byte array to long long
long long ByteArrayToInt()
{
    long long recoveredValue = 0;
    for (int i = 0; i < BUFFER_SIZE; i++)
    {
        auto byteVal = ((buffer[i]) << (8 * i));
        recoveredValue = recoveredValue + byteVal;
    }
    return recoveredValue;
}

// Test union can convert value both directions
bool TestUnion(long long value)
{
    byteunion originalUnion, recoveredUnion;
    originalUnion.value = value;


    for (int a = 0; a < BUFFER_SIZE; a++)
    {
        recoveredUnion.arr[a] = originalUnion.arr[a];
    }

    if (recoveredUnion.value != value)
    {
        printf("Union value failed");
        return false;
    }

    return true;
}


int main()
{

    long long originalValue = 2004293008363;
    originalValue = (long long)std::pow(2, 31);
    long long recoveredValue = 0;
    byteunion originalUnion;
    originalUnion.value = originalValue;


    // Loop to find failure point
    for (int i = 1; i < BUFFER_SIZE; i++)
    {
        originalValue = (long long)std::pow(2, i);

        // First check Union method
        bool unionTest = TestUnion(originalValue);
        if (!unionTest)
        {
            printf("Fail on Union at 2^%i", i);
            break; // this is never reached - union method works
        }


        // convert value to byte array
        IntToByteArray(originalValue);

        // now convert buffer back to long long
        recoveredValue = ByteArrayToInt();


        if (originalValue != recoveredValue)
        {
            printf("Fail recoving at 2^%i\n", i);
            break;  // this is reached when the original value is 2^31
        }

    }

    printf(" OriginalValue: %llu\n", originalValue);
    printf("RecoveredValue: %llu\n", recoveredValue);

    system("pause");

    return 0;
}

Upvotes: 4

Views: 9533

Answers (1)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 727047

The problem is in converting the value back. Due to integer promotions, this expression

auto byteVal = ((buffer[i]) << (8 * i));

has type int, not long long.

Add a cast to buffer[1] to fix the problem:

auto byteVal = (((long long)buffer[i]) << (8 * i));

Although using + works fine, a more common approach in combining values is to use |:

recoveredValue |= byteVal;

Upvotes: 2

Related Questions