How can one store a uint64_t in an array?

1k views Asked by At

I am trying to store a uint64_t representation of a crc64 checksum as an array.

The checksum will always be like uint64_t res = 0x72e3daa0aa188782, so the I want that to be stored as an array, char digest[8], where digest[0] is 72, digest[1] is e3... digest[7] is 82.

I attempted looping/dividing to break up the number, but that would be more appropriate if it was a smaller integer, and if the starting point was Base-10, as the starting point is Base-16, the output should but what is described above.


Update: I removed the nonsensical code and wish I can accept all three answers, as they all did what I asked. The bit shifting is what I was hoping to get as an answer so it is why it is accepted.

5

There are 5 answers

2
Support Ukraine On BEST ANSWER

Shifting and bit-wise AND can also do what you need. For instance

unsigned char digest[8];
int shift = 56;
for (int i = 0; i < 8; ++i)
{
    digest[i] = (res >> shift) & 0xff;
    shift -= 8;
}

If it's okay to change the value of res another approach is:

for (int i = 7; i >= 0; --i)
{
    digest[i] = res & 0xff;
    res >>= 8;
}
0
Shahriar Hossain On

try this:

#define INIT_LIST           \
201234567890123456,       \
12345678901234567890,     \
98765432109876543,        \
65432109887,              \
12345234512345,           \
217631276371261627,       \
12354123512453124,        \
2163521442531,            \
2341232142132321,         \
1233432112

#define STR_(...) #__VA_ARGS__
#define STR(x) STR_(x)

int main (void)
{
  uint64_t numbers[10] = { INIT_LIST };
  char array[] = STR(INIT_LIST);
  puts(array);
}
0
phuclv On

Obviously if you divide by 10 you'll get the decimal digits instead of what you expected. In this case you just want to get the underlying bits of uint64_t which can be done with a simple memcpy. But you're expecting the bytes in big endian order so you'll also need to convert to big endian first

uint64_t number = 0x72e3daa0aa188782ull;

#ifdef __unix__
uint64_t number_be = htonll(number);
#else
uint64_t number_be = htobe64(number);
#endif

char digest[8];
memcpy(&digest, &number_be , sizeof number);

In C it can also be done with a union

union Digest
{
    uint64_t res;
    char bytes[8];
} digest;
digest.res = htonll(0x72e3daa0aa188782ull); // or htobe64
// now just use digest.bytes[]

These need only a few machine instructions, hence would be far faster than looping 8 times just to get the 8 bytes

2
DYZ On

You should use division by 256, not by 10:

unsigned char digest[sizeof(uint64_t) / sizeof(char)];

for (int i = sizeof(digest) - 1; i >= 0; i--) {
   digest[i] = res % 256; // get the last byte
   res /= 256;            // get the remainder
}

// for demo purposes
for (int i = 0; i < sizeof(digest); i++) {
   printf("%x ", digest[i]); 
}

// 72 e3 da a0 aa 18 87 82 
6
Cheatah On

I think you can just use a union here.

union foo {
    uint64_t u64;
    uint8_t u8[8];
};

This saves you from having to do any conversion. You can access the 64-bit value using foo.u64 or the 8-bit values using foo.u8[0] to foo.u8[7].