0

Does anyone know of a library that provides a function that performs this logic or perhaps a method to perform this logic?

I'm trying to convert:

unsigned char test[] = "\x00\x00\x56\x4b\x7c\x8a\xc5\xde";

to:

94882212005342 / 0x0000564b7c8ac5de

I'm aware I could loop over each individual byte in test and utilize sprintf to convert each byte to string and concatenate them into a buffer with strcat and convert the buffer string to unsigned long long via strtoull. However I'm looking for something more comprehensive and simple. Is there such a way?

4 Answers4

2

It's just maths.

unsigned char test[] = "\x00\x00\x56\x4b\x7c\x8a\xc5\xde";
unsigned long long num = 
     (unsigned long long)test[0] << 56 |
     (unsigned long long)test[1] << 48 |
     (unsigned long long)test[2] << 40 |
     (unsigned long long)test[3] << 32 |
     (unsigned long long)test[4] << 24 |
     (unsigned long long)test[5] << 16 |
     (unsigned long long)test[6] <<  8 |
     (unsigned long long)test[7] <<  0;

Remember to cast to type wide enough before shifting.

You have 8 values:

 { 0x00, 0x00, 0x56, 0x4b, 0x7c, 0x8a, 0xc5, 0xde }

which in the decimal is:

 0 0 86 75 124 138 197 222

and you want to have:

 94882212005342

which is:

  94882212005342 = 0*2^56 + 0*2^48 + 86*2^40 + 75*2^32 + 124*2^24 + 138*2^16 + 197*2^8 +  222*2^0

It's a mathematical operation. You could write ex test[0] * 72057594037927936ull but that's less readable then test[0] << 56.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
1

I have done something very similar with the use of memmove or memcpy functions https://www.tutorialspoint.com/c_standard_library/c_function_memmove.htm

    long long int var = 0; 
    memmove( &var, test, sizeof(var) );

Make sure to use the correct byte order of your system.

Luke
  • 49
  • 4
0

Just for the record, you can just simply do this:

#include <stdio.h>
#include <inttypes.h>

int main(int argc, char *argv[])
{
    unsigned char test[] = "\x00\x00\x56\x4b\x7c\x8a\xc5\xde";
    uint64_t val=0;
    for(size_t i=0; i<8; i++)
      val |= (uint64_t)test[i] << (7-i)*8;
    printf("%" PRIu64 " %" PRIX64, val, val);
}
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • And optionally: `#include _Static_assert(CHAR_BITS==8, "Get a useful computer instead of that crap.");` in case you need to ward off language lawyers, DSP programmers from the 1980s or other such creatures. – Lundin Mar 12 '21 at 15:43
-1

A fun BUT NOT RECOMMENDED way of doing this. If you want a proper solution, look at KamilCuk's answer

#include <stdio.h>
#include <string.h>

// Reverse an 8-byte array  
void rev(unsigned char *s) {
    unsigned char *end = s + 7; // Evil hard coded value

    while(s<end) {
        unsigned char tmp = *s;
        *s = *end;
        *end = tmp;
        s++;
        end--;
    }
}

int main(void) {
    unsigned char test[] = "\x00\x00\x56\x4b\x7c\x8a\xc5\xde";
    rev(test);                // Reverse the array
    long l;
    memcpy(&l, test, sizeof test);
    printf("%zx\n", l);
}

Note that the standard does not dictate the byte order. This is what works on MY machine. It will be the same on most machines, but if portability to other architectures is important to you. Don't even consider this.

However, since you're saying that the value is an address, I'd recommend using uintptr_t instead of long.

klutt
  • 30,332
  • 17
  • 55
  • 95