Лучший способ инициализировать статически инициализированный для каждой структуры символьный буфер? - PullRequest
0 голосов
/ 08 февраля 2011

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

То есть, для:

#pragma pack(push, 1);

struct Header {
   int a;
   int b;
   char c;
};

struct X {
   int x;
   int y;
};

struct Y {
   char someStr[20];
};

struct Msg {
   Header hdr;
   union {
      X x;
      Y y;
   };
};

#pragma pack(pop)

У нас есть:

tempate<typename T>
struct Buffer {
    static char buffer[sizeof(T)];
}

template<class T>
inline char* get_buffer() {
  return Buffer<T>::buffer;
}

Две вещи, которые я ищу:

  1. Существует ровно 2 буфера: 1 для X и один для Y. Каждый из них должен иметь длину sizeof (Msg.hdr) + sizeof (Msg.x) и sizeof (Msg.hdr) + sizeof (Msg.y ) соответственно.
  2. Каждый буфер будет извлекаться много раз за время существования приложения, и только некоторые поля действительно (или должны) изменятся. 2а. Сообщение для X, поддерживаемое его буфером символов, должно быть инициализировано как m.hdr.a = 1, m.hdr.b = 0; а для Msg Y это должно быть m.hdr.a = 16; m.hdr.b = 1; как пример.
  3. Приложение будет часто извлекать эти буферы как Msg типа, поддерживаемые X или Y (приложение будет знать, какой именно), а затем изменять только x и y или someStr, а затем выводить их в файл, например, затем повторять.

Просто интересно, какой замечательный способ опирается на эти замечательные примеры @ 6502 и @Fred Nurk, чтобы элегантно инициализировать эти 2 буфера, читая их человеком. Я бы предпочел продолжать использовать структуры и максимально ограничить использование reinterpret_cast <> (), поскольку могут возникнуть проблемы с наложением псевдонимов.

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

Спасибо.

*** Обновление: моя схема использования этих буферов такова, что я буду отправлять копирование char * в поток или файл. следовательно мне нужно получить char * указатель на базовые данные. Однако мне нужно работать с буферами символов через их структуры для удобства чтения. Также этот буфер символов должен быть отделен и не обязательно должен содержаться или «присоединяться» к структуре, так как структуры в значительной степени находятся в отдельных файлах и используются в других местах, где буферы не нужны / не нужны. Будет просто делать простой статический X X; статический Y у; достаточно или может быть лучше буферы длины Header + X для буфера Msg X? а потом как-то просто сохранить ссылку на символ * для каждого сообщения для X и Y? Буду ли я сталкиваться с проблемами псевдонимов?

1 Ответ

1 голос
/ 08 февраля 2011

Если бы вы писали его на C, вы могли бы взглянуть на довольно распространенное расширение компилятора C, называемое «приведение к типу объединения», но в C ++ его больше нет.

В C ++ нет способа обойти reinterpret_cast <> для того, что вам нужно, но, по крайней мере, вы можете сделать это довольно безопасно, вычислив смещение члена по NULL-указателю, приведенному к объединению, и затем вычтите это смещение из вашего указателя данных до приведение его в союз. Я считаю, что на большинстве компиляторов смещение будет равно 0, но лучше быть в безопасности.

template<class T>
union Aligner {
    T t;
    char buffer[sizeof(T)];
};

template<class T>
inline char* get_buffer(T* pt) {

    return reinterpret_cast<Aligner<T>*>(reinterpret_cast<char*>(pt) - reinterpret_cast<ptrdiff_t>(&reinterpret_cast<Aligner<T>*>(NULL)->t))->buffer;
}
...