5

I'm trying to store a state in my data logger. I can read/write fine to SD, but I can't wrap my head around reading/writing a long value correctly - I've build it down to converting it to char array and back.

My best try so far has been

long temp = 1418172669L;
unsigned char buf[4];
buf[0] = temp         & 0xFF;
buf[1] = (temp >>  8) & 0xFF;
buf[2] = (temp >> 16) & 0xFF;
buf[3] = (temp >> 24) & 0xFF;

long  l = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);

But l is very different from temp - currently the output is -26371. Am I making an obvious mistake?

Blitz
  • 155
  • 1
  • 1
  • 5

3 Answers3

9

I suggest using a union:

union {
    char myByte[4];
    long mylong;
} foo;

Char to Long:

Then you can just add the bytes:

foo myUnion;
myUnion.myByte[0] = buf[0];
myUnion.myByte[1] = buf[1];
myUnion.myByte[2] = buf[2];
myUnion.myByte[3] = buf[3];

Then you can access the long as:

myUnion.myLong;

Long to Char:

The same if you want to go the other way from long to char array:

foo myUnion
myUnion.myLong = 1234L;

To access bytes:

myUnion.myByte[0];
myUnion.myByte[1];
myUnion.myByte[2];
myUnion.myByte[3];
Blitz
  • 155
  • 1
  • 1
  • 5
uniquenamehere
  • 236
  • 1
  • 3
1

I think the last expression is performed exclusively as an int expression and converted to long only at the end, i.e. before assignment to l.

long  l = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);

Here the compiler calculates buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24) as an int only.

If you give a hint to the compiler by telling it you want long expressions used, then it should work. The easiest way to do so is to replace the number of bits to be shifted as long literals:

long  l = buf[0] | (buf[1] << 8L) | (buf[2] << 16L) | (buf[3] << 24L);

That should be enough for the compiler to perform the whole operation as long and not loose precision.

jfpoilpret
  • 9,162
  • 7
  • 38
  • 54
0

Just for completeness, after posting this, I've found another way around it, but @Phataas solution is much more elegant. Using the ltoa and atol functions, long to char array and vice-verse can be done like this:

char temp[10];
ltoa(669L,temp,10);
long result = atol(temp);
Blitz
  • 155
  • 1
  • 1
  • 5