Greg M
Greg M

Reputation: 954

Safely convert 2 bytes to short

I'm making an emulator for the Intel 8080. One of the opcodes requires a 16 bit address by combining the b and c registers (both 1 byte). I have a struct with the registers adjacent to each other. The way I combine the two registers is:

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

I was thinking I can just OR them together, but that doesn't work.

short address = state.b | state.c

Another way I tried doing this was by creating a short, and setting the 2 bytes individually.

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

Is there a better/safer way to achieve what I am trying to do?

Upvotes: 4

Views: 7788

Answers (4)

M.M
M.M

Reputation: 141554

You can use:

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

Using multiplication instead of shift avoids all the issues relating to shifting the sign bit etc.

The address should be unsigned otherwise you will cause out-of-range assignment, and probably you want to use 0 to 65535 as your address range anyway, instead of -32768 to 32767.

Upvotes: 2

James Adkison
James Adkison

Reputation: 9602

As others have mentioned there are concerns with endian-ness but you can also use a union to manipulate the memory without the need to do any shifting.

Example Code

#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;
}

Example Output

263

Live Example

Upvotes: 2

Sam Varshavchik
Sam Varshavchik

Reputation: 118310

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

That's the portable way. Your way, with reinterpret_cast is not really that terrible, as long as you understand that it'll only work on architecture with the correct endian-ness.

Upvotes: 2

David Schwartz
David Schwartz

Reputation: 182763

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

Reverse the state.b and state.c if you need the opposite endianness.

Upvotes: 2

Related Questions