4

I have an unsigned char array whose size is 6. The content of the byte array is an integer (4096*number of seconds since Unix Time). I know that the byte array is big-endian.

Is there a library function in C that I can use to convert this byte array into int_64 or do I have to do it manually?

Thanks!

PS: just in case you need more information, yes, I am trying to parse an Unix timestamp. Here is the format specification of the timestamp that I dealing with.

CherryQu
  • 3,343
  • 9
  • 40
  • 65
  • You have to do it by hand which is quite easy. Since you are dabbling with byte ordering, I would suggest you read [this](http://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html) Rob Pike's blog post about it. Code that will be helpful to you is included in the article, just don't go straight for it, read it. – Francisco Soto May 16 '12 at 00:11
  • There is no standard C function to do this. It's possible that there's a function provided by whatever library it is that uses this format, though. – Oliver Charlesworth May 16 '12 at 00:00

5 Answers5

8

A C99 implementation may offer uint64_t (it doesn't have to provide it if there is no native fixed-width integer that is exactly 64 bits), in which case, you could use:

#include <stdint.h>

unsigned char data[6] = { /* bytes from somewhere */ };
uint64_t result = ((uint64_t)data[0] << 40) |
                  ((uint64_t)data[1] << 32) |
                  ((uint64_t)data[2] << 24) |
                  ((uint64_t)data[3] << 16) |
                  ((uint64_t)data[4] << 8)  |
                  ((uint64_t)data[5] << 0);

If your C99 implementation doesn't provide uint64_t you can still use unsigned long long or (I think) uint_least64_t. This will work regardless of the native endianness of the host.

dreamlax
  • 93,976
  • 29
  • 161
  • 209
0

Have your tried this:

unsigned char a [] = {0xaa,0xbb,0xcc,0xdd,0xee,0xff};
unsigned long long b = 0;
memcpy(&b,a,sizeof(a)*sizeof(char));
cout << hex << b << endl;

Or you can do it by hand which will avoid some architecture specific issues.

I would recommend using normal integer operation (sums and shifts) rather than trying to emulate memory block ordering which is no better than the solution above in term of compatibility.

Samy Arous
  • 6,794
  • 13
  • 20
0

I think the best way to do it is using a union.

union time_u{
    uint8_t data[6];
    uint64_t timestamp;
}

Then you can use that memory space as a byte array or uint64_t, by referencing

union time_u var_name;
var_name.data[i]
var_name.timestamp
0

Here is a method to convert it to 64 bits:

uint64_t
convert_48_to_64(uint8_t *val_ptr){
  uint64_t ret = 0;
  uint8_t *ret_ptr = (uint8_t *)&ret;

  for (int i = 0; i < 6; i++) {
      ret_ptr[5-i] = val_ptr[i];
  }
  return ret;
 }

 convert_48_to_64((uint8_t)&temp);  //temp is in 48 bit

eg: num_in_48_bit = 77340723707904; this number in 48 bit binary will be : 0100 0110 0101 0111 0100 1010 0101 1101 0000 0000 0000 0000 After conversion in 64 bit binary will be : 0000 0000 0000 0000 0000 0000 0000 0000 0101 1101 0100 1010 0101 0111 0100 0110 let's say val_ptr stores the base address of num_in_48_bit. Since pointer typecast to uint8_t, incrementing val_ptr will give you next byte. Looping over and copy the value byte by byte. Note, I am taking care of network to byte order as well.

vpatial
  • 33
  • 3
-1

You can use pack option

#pragma pack(1)

or

__attribute__((packed))

depending on the compiler

typedef struct __attribute__((packed))
{
    uint64_t u48: 48;
} uint48_t;

uint48_t data;

memcpy(six_byte_array, &data, 6);
uint64_t result = data.u48;

See

phuclv
  • 37,963
  • 15
  • 156
  • 475