Как выделить память для структуры с членом char * - PullRequest
3 голосов
/ 16 сентября 2011

Моя структура выглядит так:

struct tlv_msg
{
   uint8_t datatype;   //type of data
   /* data stored in a union */
   union{
     int32_t s32val;          /*  int */
     int64_t s64val;          /*  long long */
     uint32_t u32val;         /*  unsigned int */
     uint64_t u64val;         /*  unsigned long long */
     char* strval;            /*  string */
     unsigned char* binval;   /*  any binary data */
   };

   uint32_t bytelen;  /* no. bytes of union/data part */
};

Эта структура использует объединение для хранения различных типов данных. У меня есть функция alloc, которая выделяет память для структуры в куче. Правильно ли я считаю, что если я выделяю целочисленный тип (т. Е. Первые четыре типа, перечисленные выше в объединении), мне нужно выделить только следующее:

tlv_msg* msg = malloc(sizeof(tlv_msg));

sizeof (tlv_msg) возвращает 24. Я предполагаю, что этого достаточно, чтобы вместить самый большой тип данных в объединении плюс другие члены данных. (не уверен, почему 24 - кто-то может объяснить?).

Но если тип данных для хранения является указателем, например, char *, тогда мне также нужно сделать следующее:

msg->strval = (char*)malloc(sizeof(string_length+1);

Это имело бы смысл для меня, и это, кажется, работает, но просто хотел проверить.

Ответы [ 2 ]

5 голосов
/ 16 сентября 2011

Совершенно верно.

Тем не менее, вы можете создать вспомогательные функции, которые помогут вам справиться с этим.

Например:

tlv_msg * new_tlv_msg( void );

/* There, you need to free struct members, if applicable */
void delete_tlv_msg( tlv_msg * msg ); 

/* Here you may copy your string, allocating memory for it */
tlv_msg_set_strval( tlv_msg * msg, char * str );

Реализацияможет быть (основной, конечно)

tlv_msg * new_tlv_msg( void )
{
    return calloc( sizeof( tlv_msg ), 1 ); 
}

void delete_tlv_msg( tlv_msg * msg )
{
    if( msg->strval != NULL )
    {
        free( msg-strval );
    }
    free( msg );
}

tlv_msg_set_strval( tlv_msg * msg, char * str )
{
    if( msg->strval != NULL )
    {
        free( msg-strval );
    }
    msg->strval = strdup( str );
}
1 голос
/ 16 сентября 2011

Да, вы правы, выполнив два шага выделения памяти: первый для структуры и второй для строки символов.

Если это не встроенная система, в которой объем памяти ограничен, одним из способов обойти это является выбор максимального размера строки.Да, это приводит к потере памяти, если, например, у вас обычно есть только 10 символов или меньше строк и выделено, скажем, 25 символов.

#define WORKING_BUF_LEN 1024

struct tlv_msg
{
   uint8_t datatype;   //type of data
   /* data stored in a union */
   union{
     int32_t s32val;          /*  int */
     int64_t s64val;          /*  long long */
     uint32_t u32val;         /*  unsigned int */
     uint64_t u64val;         /*  unsigned long long */
     char strval[WORKING_BUF_LEN={0};            /*  string */
     unsigned char* binval;   /*  any binary data */
   };

   uint32_t bytelen;  /* no. bytes of union/data part */
};

Вы также можете выполнить собственное управление памятью, чтобы избежать фрагментации кучи, если вы планируете использовать многие из этих структур и, следовательно, множество указателей на символы *, но это требует большой работы.Вы перезаписываете новое с помощью макроса и назначаете предварительно выделенное хранилище указателю, а затем ведете учет хранения.Не делай этого, если не обязан.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...