C/C++三维数组中的DWORD转BYTE和BYTE转DWORD转换

3

我很难理解我是否在正确地做这件事,以及这是否是(唯一的)最佳解决方案。

我正在工作的项目使用三维数组来保存和使用大量数据。其中“数据”的一部分是DWORD类型的,我必须安全地进行DWORD / BYTE之间的转换。

BYTE(c风格)数组如下所示:

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

我找到的从DWORD转换为BYTE的唯一方法是:
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);

我理解DWORD是4个字节,所以char的最大长度为4。(如果我错了请纠正我?)

然后从BYTE转换回DWORD:

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

这将正常打印出:0x00542174

所以我的问题是,这一切都正确和安全吗?因为我将有大量的数据在数组中,DWORD/BYTE转换对我来说至关重要,必须准确无误。

请建议并纠正我做错的地方,我非常感激!


2
没问题,你可以忽略字节序和类型转换。 - Hans Passant
谢谢@HansPassant,那么不同的电脑(不同版本的Windows,不同的CPU)不会影响任何东西吗?在我的例子中,0x00542174的格式必须被保留...这意味着我不能承受它反过来,比如0x74124500。 - Mecanik
非常感谢,发表一个答案,这样我就可以接受它了 :) - Mecanik
2个回答

5

这段代码

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

根据C++标准,未定义行为是不被允许的。尽管一些编译器可能允许它作为扩展,但除非你想在更换编译器或命令行选项时感到惊讶,请不要使用它。
正确的方法是:
DWORD dword_data;
BYTE byte_array[sizeof(DWORD)];
memcpy(byte_array, &dword_data, sizeof(DWORD));

不用担心效率:任何一款优秀的编译器都会将此memcpy优化掉。
在C++20中,您将能够变得更简洁
auto byte_array = std::bit_cast<std::array<BYTE, sizeof(DWORD)>>(dword_data);

反向转换也应该使用 memcpy,以保证与字节序无关:在大端机器上,您的 getDwordFromBytes 将无法产生原始的 dword_data

@NorbertBoros,我希望那个投反对票的人能解释一下他的决定。如果我的回答有误,我想知道问题出在哪里。另一个回答被投反对票也让我感到困惑。 - Evg
我的猜测是负分来自于反向转换。为了保证字节序无关,最好使用memcpy进行操作,而不是单独操纵BYTE。我已将此添加到答案中。 - Evg

1

DWORD是32位无符号整数。

typedef unsigned long DWORD, *PDWORD, *LPDWORD;

32位意味着4字节,因为每个字节是8位。所以4*8=32。

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

当您将字节数组发送到某些期望以相反顺序(不同的字节序)查看这些字节的代码时,问题会发生。然后,您需要将其反转。
DWORD是Windows特定的typedef,而且所有Windows都是小端字节序,因此如果您在同一台机器上处理数据,则我认为可以安全地使用此代码。

我没有点踩,但我认为原因可能是楼主特别请求知道转换是否安全(实际上它不安全),而您的帖子并没有给出足够具体的答案。 - tay10r
@AlexV.,是的,一个人不能为自己的答案投票,那是为别人准备的。 - Evg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接