安全地将 2 个字节转换为短字节

Safely convert 2 bytes to short

我正在为 Intel 8080 制作一个仿真器。其中一个操作码需要通过组合 bc 寄存器(均为 1 字节)的 16 位地址。我有一个寄存器彼此相邻的结构。我结合两个寄存器的方式是:

using byte = char;

struct {

    ... code
    byte b;
    byte c;
    ... code

} state;

...somewhere in code    

// memory is an array of byte with a size of 65535
memory[*reinterpret_cast<short*>(&state.b)]

我想我可以 OR 把它们放在一起,但是那行不通。

short address = state.b | state.c

我尝试这样做的另一种方法是创建一个短片,然后分别设置 2 个字节。

short address;
*reinterpret_cast<byte*>(&address) = state.b;
*(reinterpret_cast<byte*>(&address) + 1) = state.c;

是否有 better/safer 方法来实现我想要做的事情?

short j;
j = state.b;
j <<= 8;
j |= state.c;

如果您需要相反的字节顺序,请反转 state.bstate.c

short address = ((unsigned short)state.b << 8) | (unsigned char)state.c;

这就是便携方式。您使用 reinterpret_cast 的方式并没有那么糟糕,只要您了解它只适用于具有正确字节顺序的体系结构。

正如其他人所提到的,存在字节序问题,但您也可以使用联合来操纵内存,而无需进行任何移位。

示例代码

#include <cstdint>
#include <iostream>

using byte = std::uint8_t;

struct Regs
{
    union
    {
        std::uint16_t bc;

        struct
        {
            // The order of these bytes matters
            byte c;
            byte b;
        };
    };
};

int main()
{
    Regs regs;

    regs.b = 1; // 0000 0001
    regs.c = 7; // 0000 0111

    // Read these vertically to know the value associated with each bit
    //
    //                             2 1
    //                             5 2631
    //                             6 8426 8421
    //
    // The overall binary: 0000 0001 0000 0111
    //
    // 256 + 4 + 2 + 1 = 263

    std::cout << regs.bc << "\n";

    return 0;
}

示例输出

263

Live Example

您可以使用:

unsigned short address = state.b * 0x100u + state.c;

使用乘法而不是移位可以避免与移动符号位等相关的所有问题

address 应该是 unsigned 否则你会导致超出范围的分配,并且你可能想使用 0 到 65535 作为你的地址范围,而不是 -32768 到 32767 .