Имеете 8-битные и 16-битные представления для одних и тех же данных?

Я работаю над эмулятором видеоигры, используя C ++.

Память представлена ​​массивом значений uint8_t. Часто мне также необходимо получить доступ к содержимому этой памяти в виде 16-битных значений (два последовательных 8-битных значения).

У меня есть что-то похожее на это:

struct Memory {

uint8_t map[0xFFFF];

// Let's say that [] is for accessing 8-bit values
uint8_t& operator[](uint16_t address) {
return map[address];
}

// () is for 16-bit values
uint16_t& operator()(uint16_t address) {
return ???; // Looking for a good implementation here
}
};

Например, если память содержит [0xC0, 0xFF, 0x66, 0xAA …], то [] вернется:

mem[0] -> 0xC0
mem[1] -> 0xFF
mem[2] -> 0x66

а также () вернется (в зависимости от порядкового номера системы):

mem(0) -> 0xFFC0
mem(1) -> 0x66FF
mem(2) -> 0xAA66

Эти методы доступа будут вызываться много. Я хотел бы использовать указатели в () для быстрого доступа. Я не хочу вычислять 16-битные значения, сдвигая и используя 8-битные пары (и я не могу, так как метод должен возвращать ссылку).

Мой вопрос: Есть ли способ в C ++ иметь разные Просмотры на том же буфере? 8-битное представление и 16-битное представление, указывающие на одни и те же данные, были бы идеальными.

(Например, JS ArrayBuffer API обеспечивает DataView, который может сделать именно это. Может быть, есть хитрый трюк для достижения этого чисто с помощью указателей в C ++?)

Моим первым предположением было использовать какой-то союз:

union mem_t {
uint8_t bytes[0xFFFF];
uint16_t words[0x8000]
}

Но тогда доступны только 16-битные значения в четных байтах:

mem.words[0] -> 0xFFC0

mem.words[1] -> 0xAA66 // Should be 0x66FF :(

Рабочим решением является наличие двух дополнительных 16-битных указателей для четных и нечетных адресов для обработки перекрытие:

uint16_t* even16 = (uint16_t*) map;
uint16_t* odd16 = (uint16_t*) (map + 1);

uint16_t& Memory::operator()(uint16_t address) {
return address % 2 ? odd16[address / 2] : even16[address / 2];
}

Это работает отлично, но кажется очень запутанным, и я уверен, что есть более элегантные решения.

Благодарю.

1

Решение

что-то вроде этого, но вы можете нарушить правила выравнивания памяти в вашей хост-системе:

struct Memory {

uint8_t map[0xFFFF];

// Let's say that [] is for accessing 8-bit values
uint8_t& operator[](uint16_t address) {
return map[address];
}

// () is for 16-bit values
uint16_t& operator()(uint16_t address) {
return *reinterpret_cast<uint16_t*>(&map[address]);
}
};
0

Другие решения