Как правильно читать / заполнять буферы данных, используя структуры сообщений в c ++?

0

У меня есть программа, которая обрабатывает буферы char [] для отправки/получения сообщений. До сих пор так оно и было:

#pramga pack(1)
struct messageType
{
    uint8_t data0:4;
    uint8_t data1:4;
    uint8_t data2;
    //etc...
};
#pragma pack()

void MyClass::processMessage(char* buf)
{
    // I already know buf is big enough to hold a messageType
    messageType* msg = reinterpret_cast<messageType*>(buf);

    //populate class member variables
    m_data0 = msg->data0;
    m_data1 = msg->data1;
    m_data2 = msg->data2;
    //etc  
}

Теперь из того, что я собрал из чтения, является то, что это технически неопределенное поведение из-за строгого сглаживания, и вместо этого следует использовать memcpy? Я не совсем понимаю, какие потенциальные проблемы копируют buf байт для байта в messageType msgNotPtr, а затем считывают из этого msgNotPtr, на самом деле избегают?

Что касается отправки, вместо этого:

void MyClass::sendMessage()
{
    char buf[max_tx_size];
    messageType* msg = reinterpret_cast<messageType*>(buf);

    msg->data0 = m_data0;
    //etc...
    send(buf);
}

Я читал, что должен использовать placement new isntead, ala:

messageType* msg = new(buf) messageType;

Если я так делаю, мне нужно добавить дополнительную очистку, учитывая, что struct messageType содержит только типы POD (например, вручную messageType деструктор)?

Изменение: Теперь, когда я думаю об этом, sendMessage все еще не определен? Нужно ли мне также поменять последнюю команду на что-то вроде send(reinterpret_cast<char*>(msg)) чтобы убедиться, что компилятор не оптимизирует вызов?

  • 0
    Учитывая предоставленный вами код, я бы сказал, что вам не нужно вручную вызывать деструктор, поскольку buf размещается в стеке. Вы имеете дело с POD, поэтому единственной причиной вызова деструктора является освобождение выделенной памяти, а здесь это не требуется.
  • 0
    @bialpio Это не имеет никакого отношения к тому, находится ли буфер в стеке или нет. Я не знаю, требуется ли вызывать деструктор при использовании нового размещения с POD.
Показать ещё 2 комментария
Теги:

1 ответ

0

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

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

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

Таким образом, укусите производительность на входе и выходе, разместив элементы, где вы хотите их в буфере (или извлечение элементов в соответствии со спецификацией). Остальная часть программы может получить доступ к элементам так, как компилятор их согласовал.

Это включает в себя поля бит.

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

  • 0
    Мой вопрос более или менее о том, как извлечь элементы из буфера, в соответствии со спецификацией. Я чувствую, что приведение к упакованной структуре, чтобы сделать это, намного проще, чем эквивалентные побитовые операции, которые я должен был бы сделать, чтобы получить элементы, которые смещены на 2, 4 и т. Д.
  • 0
    Полагаю, я должен заметить, что члены моего класса не упакованы, есть только промежуточный messageType , который используется для заполнения переменных класса.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню