У меня есть программа, которая обрабатывает буферы 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))
чтобы убедиться, что компилятор не оптимизирует вызов?
На мой взгляд, правильный способ загрузить экземпляр класса из буфера uint8_t - загрузить каждый элемент отдельно.
Класс должен знать положения своих членов в буфере и где и размер любых отступов или зарезервированных областей.
Одна из проблем, связанных с структурами сопоставлений с буферами, заключается в том, что компилятор может добавлять пространство между членами. Если вы упаковываете структуру для исключения заполнения, вы замедляете свою программу каждый раз, когда получаете доступ к члену.
Таким образом, укусите производительность на входе и выходе, разместив элементы, где вы хотите их в буфере (или извлечение элементов в соответствии со спецификацией). Остальная часть программы может получить доступ к элементам так, как компилятор их согласовал.
Это включает в себя поля бит.
Кроме того, благодаря тому, что члены загружаются индивидуально, Endianess полей в буфере может быть намного проще.
messageType
, который используется для заполнения переменных класса.
buf
размещается в стеке. Вы имеете дело с POD, поэтому единственной причиной вызова деструктора является освобождение выделенной памяти, а здесь это не требуется.