Сопоставьте макет с адресом памяти - PullRequest
1 голос
/ 18 июня 2020

В C ++ есть способ «сопоставить» желаемый макет с данными в памяти, без его копирования в память?

Т.е. существует void* buffer, и я знаю его макет :

  • byte1: uint8_t
  • byte2-3: uint16_t
  • byte4: uint8_t

Я знаю, что могу создать структуру, и запишите данные в структуру, а затем я могу иметь значения в виде полей структуры.

Но есть ли способ добиться этого без копирования? Данные уже есть, мне просто нужно получить несколько полей, и я ищу способ что-то, что может помочь с разметкой.

(у меня может быть несколько static int s для смещений памяти, но Я надеюсь на еще несколько общих c).

Т.е.: у меня было бы больше «макетов», и в зависимости от типа необработанных данных я бы сопоставил соответствующий макет и получил доступ к его полям, которые все еще указывает на исходные данные.

Я знаю, что могу указывать структуры на данные, это просто:

struct message {
    uint8_t type;
};
struct request:message {
    uint8_t rid;
    uint8_t other;
};
struct response:message {
    uint8_t result;
};

vector<uint8_t> data;
data.push_back(1); //type
data.push_back(10);
data.push_back(11);
data.push_back(12);
data.push_back(13);

struct request* ptrRequest;

ptrRequest = (struct request*)&data[1];
cout << (int)ptrRequest->rid; //10
cout << (int)ptrRequest->other; //11

Но я бы хотел получить карту с макетами , то есть:

map<int, struct message*> messagetypes;

Но я понятия не имею, как я могу продолжить, поскольку для установки потребуется новый объект, а кастинг также является сложной задачей, если на картах хранятся только базовые указатели.

Ответы [ 2 ]

2 голосов
/ 18 июня 2020

Если ваша структура макета - POD, вы можете выполнить размещение new-expression без инициализации, которое служит маркером создания объекта. Например:

#include <new> // Placement new.
// ...
uint8_t* data = ...; // Read from disk, network, or elsewhere.
static_assert(std::is_pod<request>::value, "struct request must be POD.");
request* ptrRequest = new (static_cast<void*>(data)) request;

Это работает только с POD. Это давняя проблема, описанная в P0593R6 Неявное создание объектов для низкоуровневых манипуляций с объектами .

Если ваша целевая архитектура требует выравнивания данных, добавьте проверку выравнивания указателя data .


Как указано в другом ответе, memcpy может быть исключено компилятором, проверьте вывод сборки.

2 голосов
/ 18 июня 2020

В C ++ есть ли способ «сопоставить» желаемый макет с данными в памяти, не копируя их в память?

Нет, не в стандартном C ++.

Если макет совпадает с макетом класса 1 , то, возможно, вы сможете сначала записать данные памяти в экземпляр класса, чтобы потом их не нужно было копировать.

Если описанное выше невозможно, то вы можете скопировать (да, это memcopy, но придерживаться этой мысли) данные на автоматический c экземпляр класса, а затем разместить новую копию automati c экземпляр в исходный массив. Хороший оптимизатор может видеть, что эти копии взад и вперед не изменяют значение, и может оптимизировать их. Здесь также необходима соответствующая раскладка. Пример:

struct data {
    std::uint8_t  byte;
    std::uint8_t  another;
    std::uint16_t properly_aligned;
};

void* buffer = get_some_buffer();
if (!std::align(alignof(data), sizeof(data), buffer, space))
    throw std::invalid_argument("bad alignment");

data local{};
std::memcpy(&local, buffer, sizeof local);
data* dataptr = new(buffer) data{local};
std::uint16_t value_from_offset = dataptr->properly_aligned;

https://godbolt.org/z/uvrXS2 Обратите внимание, что в сгенерированной сборке нет вызова std::memcpy.

Здесь следует учитывать, что multi -байтовые целые числа должны иметь тот же порядок байтов, что и ЦП изначально. Следовательно, данные не переносятся между системами (с разным байтовым кодом). Для переносимости требуется более продвинутая десериализация.


1 Однако маловероятно, что данные могут соответствовать макету класса, потому что второй элемент - uint16_t не выравнивается по двум 16-битной границе от начала макета.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...