【问题标题】:Safely convert 2 bytes to short安全地将 2 个字节转换为短字节
【发布时间】:2016-05-12 01:59:44
【问题描述】:

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

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;

有没有更好/更安全的方法来实现我想要做的事情?

【问题讨论】:

    标签: c++ pointers casting byte short


    【解决方案1】:
    short j;
    j = state.b;
    j <<= 8;
    j |= state.c;
    

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

    【讨论】:

    • 这可能会导致未定义的行为
    • @M.M 怎么样?您的意思是因为short 已签名?
    【解决方案2】:
    short address = ((unsigned short)state.b << 8) | (unsigned char)state.c;
    

    这就是便携的方式。你使用reinterpret_cast 的方式并没有那么糟糕,只要你明白它只适用于具有正确字节序的架构。

    【讨论】:

    • 对齐问题比字节序问题更严重。
    • 好吧,short 会适当对齐,所以我看不到那里的问题。
    • 我正在回复您的最后一句话,这就像说可以过马路而不看两边,因为您不太可能被飞机撞到。你把他指向一个小问题,却忽略了一个大问题。
    • reinterpret_cast 方式是UB,因为违反了严格的别名规则
    【解决方案3】:

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

    示例代码

    #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

    【讨论】:

      【解决方案4】:

      你可以使用:

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-02-09
        • 2020-03-23
        • 2013-06-08
        • 1970-01-01
        • 1970-01-01
        • 2021-03-14
        • 2011-01-22
        相关资源
        最近更新 更多