Reputation: 817
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
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