【问题标题】:C/C++ DWORD to BYTE and BYTE to DWORD conversion in Three-Dimensional Array三维数组中的 C/C++ DWORD 到 BYTE 和 BYTE 到 DWORD 转换
【发布时间】:2019-11-16 10:00:17
【问题描述】:

我很难理解我是否以正确的方式执行此操作,以及这是否是(唯一)最佳解决方案。

我正在进行的项目是使用Three-Dimensional Array 来保存和使用大量数据。 “数据”的一部分是 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 BYTE,这就是字符最大长度为 4 的原因。(如果我错了,请纠正我?)

然后将 从 BYTE 转换回 DWORD(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]));

打印效果很好:0x00542174

所以我的问题是,这一切是否正确和安全?因为我会在数组中有很多数据,而 DWORD/BYTE 转换对我来说是必须的,它必须是准确的。

请指正并纠正我做错的地方,我将不胜感激!

【问题讨论】:

  • 没关系,你可以忽略字节序并输入双关语。
  • 感谢@HansPassant,所以不同的PC(不同版本的windows,不同的CPU)不会影响任何东西吗?在我的示例中,必须保留 0x00542174 的格式......这意味着我不能像 0x74124500 那样将其倒退。
  • 非常感谢,发布一个答案,以便我接受它:)

标签: c++ c arrays


【解决方案1】:

这段代码

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

根据 C++ 标准是undefined behavior。一些编译器可能允许它作为扩展,但除非您想在更改编译器或命令行选项时感到惊讶,否则不要使用它。

正确的做法是:

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

不用担心效率:这个memcpy 将被任何体面的编译器优化出来。

在 C++20 中,您将能够成为 more eloquent

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

还应该使用memcpy 来完成反向转换,使其与字节序无关:您的getDwordFromBytes 将无法在大字节序机器上生成原始dword_data

【讨论】:

  • @NorbertBoros,我希望反对者能解释他的决定。如果答案不正确,我想知道问题是什么。我也不清楚对另一个答案的否决。
  • 我的猜测是,downvote 来自反向转换。为了与字节序无关,最好也使用memcpy 来完成,而不是使用单独的BYTEs 进行操作。我将此添加到答案中。
【解决方案2】:

DWORD 是 32 位无符号整数。

typedef unsigned long DWORD, *PDWORD, *LPDWORD;

32 位表示 4 个字节,因为每个字节是 8 位。而4*8=32

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

当您将字节数组发送到一些期望以相反顺序(不同字节序)查看这些字节的代码时,就会出现问题。然后,您需要将其反转。

DWORD 是特定于 windows 的 typedef,并且所有 windows 都是 little-endian,所以如果您在同一台机器上处理数据,我认为按原样使用此代码是安全的。

【讨论】:

  • 没有投反对票,但我认为这可能是因为 OP 特别要求知道转换是否安全发生(事实并非如此),并且您的帖子并没有真正具体到回答这个问题。
  • @AlexV.,是的,一个人不能投票给他自己的答案,那是给别人的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-21
  • 1970-01-01
  • 1970-01-01
  • 2016-11-12
  • 2014-12-24
  • 2021-06-24
相关资源
最近更新 更多