如何为具有char*成员的结构分配内存

3

我的结构体看起来像这样:

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 */
};

这个结构体使用联合体来保存不同的数据类型。我有一个分配函数,它在堆上为结构体分配内存。如果我为整数类型(即联合体中的前四种类型)分配内存,我的想法是只需要按如下方式进行分配,这样正确吗?
tlv_msg* msg = malloc(sizeof(tlv_msg));

sizeof(tlv_msg)的返回值为24。我猜这应该足以容纳联合中最大的数据类型加上其他数据成员。(不确定为什么是24 - 有人能解释一下吗?)。

但如果要存储的数据类型是指针类型,比如char*,那么我还需要做以下操作:

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

我觉得这样做很有道理,看起来也可行,但想确认一下。


24确实是奇数。除非您有一个64位系统并且您的编译器正在进行64位填充(我认为他们不会这样做),否则我看不出它如何能给您24! - Shahbaz
顺便说一下,在我的MinGW上它返回16,考虑到datatype后面的3字节填充是有道理的。 - Shahbaz
@Shahbaz:如果正在使用MSVC,则默认为8字节对齐,因此在数据类型后可能会有7个字节,然后在bytelen后面有4个字节。 - tinman
我正在使用 MSVC v6。如果我执行 #pragma pack(push, 4),结构体大小将从 24 变为 16。 - Angus Comber
该联合体包含一个64位成员,因此它必须(至少)按模8对齐。这迫使“datalen”成员和整个结构大小都按模8对齐。针对OP:您正在混合使用C和C ++。不要这样做。 - wildplasser
2个回答

5

这完全正确。

话虽如此,您可能希望创建辅助函数,以帮助您处理这个问题。

例如:

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

是的,你说得对,需要执行两个内存分配步骤,第一个是为结构体分配内存,第二个是为字符字符串分配内存。

除非这是一个嵌入式系统,内存空间很有限,否则可以通过确定最大字符串大小来解决这个问题。是的,这样会浪费内存,例如,如果通常只有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 */
};

如果您计划拥有许多这些结构体和许多char*指针,则可以进行自己的内存管理以避免碎片化堆,但这需要大量工作。您可以使用宏覆盖new并将预分配的存储分配给指针,然后进行存储分配簿记。除非必须这样做,否则不要这样做。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接