3

I am struggling to understand if I am doing this the correct way and if this is the (only) best solution.

The project I am working on is using a Three-Dimensional Array to hold and use lots of data. One part of the "data" is DWORD type and I must have a safe conversion from/to DWORD/BYTE.

The BYTE (c style) array looks like this:

BYTE array_data[150][5][255] = 
{
    {
        { // bytes },
        { 0x74,0x21,0x54,0x00 }, // This is converted from DWORD like: 0x00542174
        { // bytes },
        { // bytes },
        { // bytes },
    },
};

The (only) way to convert from DWORD to BYTE(s) I found:

DWORD dword_data;
char byte_array[4];

*(DWORD*)byte_array = dword_data; // byte_array becomes {0x74, 0x21, 0x54, 0x00}

wchar_t temp[256];

wsprintfW(temp, L"{0x%02x,0x%02x,0x%02x,0x%02x}, // This is converted from DWORD like: 0x%.8X\n", (BYTE)byte_array[0], (BYTE)byte_array[1], (BYTE)byte_array[2], (BYTE)byte_array[3], (DWORD)dword_data);

From I understand DWORD is 4 BYTE so that's why the char max length is 4. (correct me if I`m wrong?)

Then to convert back to DWORD from BYTE(s):

//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);
};

printf("dword_data: 0x%.8X\n", getDwordFromBytes(array_data[0][1]));

Which prints out fine: 0x00542174.

So my question is, is all this correct and safe ? Because I will have lots of data in the array and the DWORD/BYTE conversion for me is imperative, it must be accurate.

Please advise and correct me where I`m doing things wrong, I would very much appreciate it!

Mecanik
  • 1,539
  • 1
  • 20
  • 50
  • 2
    It's fine, you can ignore endian-ness and type punning. – Hans Passant Nov 16 '19 at 10:02
  • Thanks @HansPassant, so different PC's (different version of windows, different CPU) won't affect anything ? In my example, the format of 0x00542174 must be preserved... meaning I cannot afford to have it backwards like 0x74124500 for example. – Mecanik Nov 16 '19 at 10:08
  • Thanks a lot, post an answer so I can accept it :) – Mecanik Nov 16 '19 at 10:14

2 Answers2

5

This code

DWORD dword_data;
char byte_array[4];
*(DWORD*)byte_array = dword_data;

is undefined behavior according to the C++ standard. Some compilers may allow it as an extension, but unless you want to be surprised when you change a compiler or command line options, don't use it.

The correct way is:

DWORD dword_data;
BYTE byte_array[sizeof(DWORD)];
memcpy(byte_array, &dword_data, sizeof(DWORD));

Don't worry about efficiency: this memcpy will be optimized out by any decent compiler.

In C++20 you'll be able to be more eloquent:

auto byte_array = std::bit_cast<std::array<BYTE, sizeof(DWORD)>>(dword_data);

The backwards conversion should also be done using memcpy to be endianness-independent: your getDwordFromBytes will fail to produce the original dword_data on a big-endian machine.

tay10r
  • 4,234
  • 2
  • 24
  • 44
Evg
  • 25,259
  • 5
  • 41
  • 83
  • @NorbertBoros, I hope the downvoter will explain his decision. If the answer is incorrect, I would like to know what the problem is. The downvote on another answer is also not clear to me. – Evg Nov 16 '19 at 11:44
  • My guess is that downvote comes from the backwards conversion. To be endianness-independent, it better also be done using `memcpy`, rather than manipulating with separate `BYTE`s. I added this into the answer. – Evg Nov 16 '19 at 11:51
1

DWORD is 32-bit unsigned integer.

typedef unsigned long DWORD, *PDWORD, *LPDWORD;

32-bit means 4 bytes, because each byte is 8 bit. And 4*8=32

https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/262627d8-3418-4627-9218-4ffe110850b2

The problem will happen when you send your byte array to some code that expects to see those bytes in reversed order (different endianness). You would then need to reverse it.

DWORD is windows specific typedef, and all windows are little-endian, so I think it's safe to use this code as is, if you process data on the same machine.

rtxndr
  • 872
  • 1
  • 9
  • 20
  • Didn't down vote but I think it might be because the OP specifically requested to know if the conversion is happening safely (which it isn't) and your post doesn't really get specific enough to answer that question. – tay10r Nov 16 '19 at 12:52
  • @AlexV., yeah, one can't vote for his own answers, that was for someone else. – Evg Nov 16 '19 at 14:12