Структуры с динамическим распределением памяти в C - PullRequest
0 голосов
/ 09 сентября 2011

Мне нужно записать данные в структуру, где длина данных зависит от команды, которую я хочу отправить на устройство.Для этого я определил следующую структуру:

typedef struct {
    uint8 len;          // Command length (cmd ... crc)
    uint8 cmd;          // Command code
    uint8 data_length;  // Data length
    uint8 data[12];     // Data: max 12 Byte
    uint8 crc_h;        // CRC value MSB
    uint8 crc_l;        // CRC value LSB
}CMD_TYPE;

Примечание: члены cmd , * data_length * и crc , которые всегдаприсутствует, вместо этого элемент data может быть пустым или содержать до 12 байт.

Я создал функцию, которая возвращает инициализированную команду в соответствии с параметрами, переданными в функцию:

CMD_TYPE Device::get_cmd(uint8 cmd, uint8 data_len, uint8 *data)
{
    CMD_TYPE cmd;

    cmd.len = (4 + data_len) * sizeof(uint8);
    cmd.cmd = cmd;
    cmd.data_length = data_len;
    cmd.data = (uint8 *)realloc(cmd.data, data_len*sizeof(uint8));
    if(data_len > 0)    memcpy(cmd.data, data, data_len);

    add_crc16((uint8*)&cmd);

    return cmd;
}

Функция get_cmd () используется следующим образом:

uint8 cmd_code = 0x01;
uint8 data[2] = {0xAB, 0xCD};

CMD_TYPE cmd = local_device->get_cmd(cmd_code, 2, data);
retVal = local_device->send(cmd);

Когда я пытаюсь скомпилировать этот код, я получаю сообщение об ошибке от компилятора для этой строки:

cmd.data = (uint8 *)realloc(cmd.data, data_len*sizeof(uint8));

и ошибка компилятора:

error: lvalue required as left operand of assignment

Цель использования realloc () - изменить размер данных массива или вообще удалить его из моей новой структуры команд.Что не так в моем коде?Это правильный способ инициализации структур с динамическим распределением памяти?

Ответы [ 3 ]

2 голосов
/ 09 сентября 2011

То, что вы хотите, это печально известный struct hack :

typedef struct
{
    uint8   len;          // Command length (cmd ... crc)
    uint8   cmd;          // Command code
    uint8   data_length;  // Data length
    uint8   crc_h;        // CRC value MSB
    uint8   crc_l;        // CRC value LSB
    uint8   data[1];      // Data: max 12 Byte
} CMD_TYPE;

Хитрость заключается в том, чтобы выделить достаточно места для всех членов структуры доdata[], затем добавьте достаточно байтов для члена data[]:

CMD_TYPE * allocCmd(int dataSize)
{
    int         len;
    CMD_TYPE *  p;

    len = sizeof(CMD_TYPE) + (dataSize-1)*sizeof(uint8);
    p = (CMD_TYPE *) malloc(len);
    memset(p, 0, len);
    p->data_length = dataSize;
    return p;
}

Здесь len рассчитывается как размер структуры, минус размер пустого data члена,плюс, однако, множество элементов, dataSize указывает для массива data.

Подвох в том, что вы должны быть осторожны никогда , чтобы получить доступ к любым элементам p->data[] сверх того, что фактически выделенов нем (внутри структуры).

1 голос
/ 09 сентября 2011

Ваш CMD_TYPE.data является массивом , а не указателем .Поскольку вы хотите, чтобы он отслеживал динамически распределенную память, он должен быть указателем:

uint8_t * data;

Просто не забудьте инициализировать его с помощью malloc() (или установив его в ноль перед realloc())и убирать за собой

Кстати, не разыгрывает результат malloc() и со

0 голосов
/ 09 сентября 2011
Массив

, определенный как [..], является неизменным, вы не можете ничего ему присвоить.Вместо этого вы должны использовать указатели.

...