Страницы

Поиск по вопросам

четверг, 25 октября 2018 г.

Преобразование указателя на одномерный массив в указатель на двумерный

В общем, для чего всё это нужно: есть почти полностью реализованный эмулятор CHIP8. Оперативная память у него состоит из ячеек, размером в 1 байт, и предоставляет диапазон адресов от 000h до FFFh. Я её объявил как:
unsigned char memory[0x1000];
Видеопамять же находится в той же оперативной памяти с некоторым смещением, и занимает диапазон от F00h до FFFh.
Если к оперативной памяти удобно обращаться как к одномерному массиву, то к видеопамяти удобнее обращаться как к двумерному массиву типа bool[][] (потому, что дисплей монохромный, и его пиксели имеют два состояния — "чёрный" и "белый").
Как правильно и безопасно получить указатель на двумерный массив [32][64] из указателя на одномерный? Одномерный же массив получить легко:
bool *videomem = (bool *)memory + 0xF00;
А вот двумерный массив уже не получается:
bool *video_mem[64] = (bool *[64])memory + 0xF00;
Можно, конечно, создавать для видеопамяти отдельный массив (и многие программы адекватно работают), но это снижает точность эмуляции (некоторые программы могут писать напрямую в видеопамять CHIP8).


Ответ

Попробуйте так: unsigned char memory[0x1000];
const size_t video_mem_row_size = 64; // или 0x40, раз уж всё в hex const size_t video_mem_offset = 0xF00; typedef unsigned char video_mem_row[video_mem_row_size];
video_mem_row* video_mem = (video_mem_row*)(memory + video_mem_offset); Проверка: http://ideone.com/mpflzb Если у вас 64 — это размер в битах, и вы оперируете битами, вам, судя по всему, понадобится немного другой код. unsigned char memory[0x1000] = {}; // обязательно инициализируйте!
const size_t bits_in_byte = 8; const size_t video_mem_offset = 0xF00;
const size_t video_mem_row_bitsize = 0x40; const size_t video_mem_row_stride = (video_mem_row_bitsize + (bits_in_byte - 1)) / bits_in_byte;
typedef unsigned char video_mem_row[video_mem_row_stride];
video_mem_row* video_mem = (video_mem_row*)(memory + video_mem_offset);
const size_t video_mem_number_of_rows = 0x20;
bool get_video_bit(size_t row, size_t col) { if (row >= video_mem_number_of_rows || col >= video_mem_row_bitsize) throw std::invalid_argument("index"); unsigned char* p = &video_mem[row][col / bits_in_byte]; unsigned char mask = ((unsigned char)1) << col % bits_in_byte; return *p & mask; }
void set_video_bit(size_t row, size_t col, bool value) { if (row >= video_mem_number_of_rows || col >= video_mem_row_bitsize) throw std::invalid_argument("index"); unsigned char* p = &video_mem[row][col / bits_in_byte]; unsigned char mask = ((unsigned char)1) << col % bits_in_byte; if (value) *p |= mask; else *p &= ~mask; } Проверка: http://ideone.com/2BBcM1 Я бы посоветовал обернуть это в класс. Если хотите, можно написать индексаторы в духе std::vector

Комментариев нет:

Отправить комментарий