0

In one of my tasks I need to store DWORD into BYTE(s) and then convert them back. Platform is windows only.

I have found the following on this website:

//Convert an array of four bytes into a 32-bit integer.
DWORD getDwordFromBytes(BYTE* b)
{
    return (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
};

This works for converting 4 bytes into 1 DWORD, however how would you do this for DWORD64 ?

I have tried the following but it's not returning correctly as I am losing data:

DWORD64 getDwordFromBytes64(BYTE* b)
{
    return ((DWORD64)b[0]) | ((DWORD64)b[1] << 8) | ((DWORD64)b[2] << 16) | ((DWORD64)b[3] << 24);
};

Suppose I have a byte array:

BYTE[] = {0x38,0xf0,0x07,0x40,0x01,0x00,0x00,0x00}; //000000014007F038

I need to get 000000014007F038 (DWORD64) back from it correctly.

If someone would give me a solution I would very much appreciate it.

Update:

  • I can accept any solution wheter C or C++.
  • "Endianness" can be ignored.
Alan B
  • 4,086
  • 24
  • 33
Mecanik
  • 1,539
  • 1
  • 20
  • 50
  • 4
    If you figure out the endianness, `std::memcpy` may work just fine. – Max Langhof Nov 20 '19 at 09:41
  • 4
    Just continue the pattern until you handle the 8 bytes. – AProgrammer Nov 20 '19 at 09:42
  • Thanks for the prompt response guys, I added an "update" where I state that c or c++ is fine, and endian-ess can be ignored. – Mecanik Nov 20 '19 at 09:44
  • 1
    Your first step should be to understand how the 32-bit version works. Then you can easily generalise that to any bit width. – molbdnilo Nov 20 '19 at 09:47
  • A very simple and powerful way to do this, create a union which contains the byte array and the DWORD64 you are after then when you copy your bytes to the array the 64bit DWORD will automatically be populated. – SPlatten Nov 20 '19 at 09:48
  • @molbdnilo You are absolutely right, however I do not (yet) understand shifting properly :) – Mecanik Nov 20 '19 at 09:48
  • @SPlatten Sounds very interesting, post your answer ? – Mecanik Nov 20 '19 at 09:48
  • 4
    `getDwordFromBytes` has a bug in it. It invokes undefined behavior if `b[3] > 127`, because it will overflow the integer promoted expression `(b[3] << 24)`. – mch Nov 20 '19 at 09:58
  • @NorbertBoros Then learning about bit manipulation should be your very first step. – molbdnilo Nov 20 '19 at 09:59
  • To fix the bug pointed out by @mch, add an explicit cast : `(((uint32_t) b[3]) << 24)` (or if you must use non-standard types : `(((DWORD) b[3]) << 24)`). You should probably do this for the others as well. – Sander De Dycker Nov 20 '19 at 10:19
  • Thank you for all for the attention and your willingness to help, but if you have a good solution could you not post an answer ? – Mecanik Nov 20 '19 at 10:20

1 Answers1

3

if you care about the endianness and do not want to use any pointer or union punning

#define to64b(arr) (((uint64_t)(((uint8_t *)(arr))[7]) <<  0)+\ 
                    ((uint64_t)(((uint8_t *)(arr))[6]) <<  8)+\
                    ((uint64_t)(((uint8_t *)(arr))[5]) << 16)+\
                    ((uint64_t)(((uint8_t *)(arr))[4]) << 24)+\
                    ((uint64_t)(((uint8_t *)(arr))[3]) << 32)+\
                    ((uint64_t)(((uint8_t *)(arr))[2]) << 40)+\
                    ((uint64_t)(((uint8_t *)(arr))[1]) << 48)+\
                    ((uint64_t)(((uint8_t *)(arr))[0]) << 56))

#define to64l(arr) (((uint64_t)(((uint8_t *)(arr))[0]) <<  0)+\ 
                    ((uint64_t)(((uint8_t *)(arr))[1]) <<  8)+\
                    ((uint64_t)(((uint8_t *)(arr))[2]) << 16)+\
                    ((uint64_t)(((uint8_t *)(arr))[3]) << 24)+\
                    ((uint64_t)(((uint8_t *)(arr))[4]) << 32)+\
                    ((uint64_t)(((uint8_t *)(arr))[5]) << 40)+\
                    ((uint64_t)(((uint8_t *)(arr))[6]) << 48)+\
                    ((uint64_t)(((uint8_t *)(arr))[7]) << 56))

uint64_t toUnsigned64(const void *arr, int bigend)
{
    return bigend ? to64b(arr) : to64l(arr);   
}
0___________
  • 60,014
  • 4
  • 34
  • 74
  • Right, my bad, all those parenthesis made it unreadable. I'd consider fixing by adding a temp pointer in the function: `const uint8_t* u8 = arr;`, then voila each line in the macro can get simplified into `((uint64_t)arr[7] << 56)`. Or if being pedantic about macro safety, `((uint64_t)(arr)[7] << 56)` – Lundin Nov 20 '19 at 12:24