Динамически распределять память для массивов в объединении в C ++ - PullRequest
0 голосов
/ 09 апреля 2020

Я использую union для заполнения некоторых полей сообщения в буфере сообщений типа char. Если длина сообщения постоянна, оно работает правильно. См. Упрощенный пример кода ниже.

Проблема в том, что мое сообщение может иметь переменную длину. В частности, const N будет определено во время выполнения. Есть ли способ продолжать использовать союзы, динамически выделяя память для buf?

Я изучаю умные указатели, но пока мне не повезло.

const int N = 4;

struct repeating_group_t {
  uint8_t field1;
  uint8_t field2;
}rpt_group;

struct message_t
{
    union
    {
        char buf[2 + 2*N];
        struct {
          uint8_t header;
          uint8_t block_len;
          std::array<repeating_group_t, N> group;
        };
    };
};

int main()
{ 
    message_t msg;

    msg.header    = 0x32;
    msg.block_len = 8;

    for (auto i = 0; i < N; i++)
    {
      msg.group[i].field1 = i;
      msg.group[i].field2 = 10*i;
    } 

    // msg.buf is correctly filled

    return 0;
}

Ответы [ 2 ]

1 голос
/ 10 апреля 2020

Как сказано в комментариях, используйте std::vector.

int main() {
     // before C++17 use char
     std::vector<std::byte> v.
     v.push_back(0x32);
     v.push_back(8);
     for (auto i = 0; i < N; i++) {
         v.push_back(i);
         const uint16_t a = 10 * i;
         // store uint16_t in big endian
         v.push_back(a >> 16);
         v.push_back(a & 0xff);
     } 
}

. Для пользовательских типов данных вы можете предоставить свой собственный потоковый или контейнерный контейнер и перегрузить operator>> или другую пользовательскую функцию: ваш выбор для ваших типов данных.

struct Message{
    std::vector<std::byte> v; 
    Message& push8(uint8_t t) { ... }
    // push 16 bits little endian
    Message& push16le(uint16_t t) { ... }
    // push 16 bits big endian
    Message& push16be(uint16_t t) { ... }
    // etc
    Message& push(const Repeating_group& t) {
       v.push_back(t.field1);
       v.push_back(t.field2);
       return v;
    }
    // etc.
};

int main(){ 
     Message v;
     v.push8(0x32).push8(8);
     for (...) {
         v.push(Repeating_group(i, i * 10));
     }
 }
0 голосов
/ 09 апреля 2020

Нельзя вычислять N во время выполнения, потому что и c -array (ваш buf), и std::array имеют информацию о размере в своем типе.

Также - использование union для (de) Сериализация не является хорошей практикой - размер вашей структуры будет зависеть от выравнивания, необходимого на данной машине, для которой она скомпилирована и т. д. Вы можете добавить атрибут packed, чтобы преодолеть его, но у вас все еще есть много проблем с зависимостью платформы .

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

Где вы хотите передать эти сообщения?

...