使用指针作为结构成员将struct序列化为字节数组

时间:2015-06-17 01:40:21

标签: c

我正在尝试将一个字节数组复制到我的struct中,然后再次将我的struct序列化为一个字节数组。

但是,在我序列化我的struct数组后,我再也无法得到我的数据值(0x12,0x34,0x56),而是得到一些垃圾数据。

这里有什么问题?

#pragma pack(push, 1)
typedef struct {
    uint8_t length;
    uint8_t *data;
} Tx_Packet;
#pragma pack(pop)

static void create_tx_packet(uint8_t *packet, uint8_t *src, int length);

int main(void)
{
    uint8_t packet[32];
    uint8_t data[] = { 0x12, 0x34, 0x56 };

    create_tx_packet(packet, data, 3);

    //i check using debugger, i cant get the data value correctly
    //but i could get length value correctly


    return 0;
}

static void create_tx_packet(uint8_t *packet, uint8_t *src, int length)
{
    Tx_Packet *tx_packet = malloc(sizeof(*tx_packet ));

    tx_packet->length = length;
    tx_packet->data = (uint8_t *)malloc(length);
    memcpy(tx_packet->data, src, length);

    memcpy(packet, tx_packet, sizeof(*tx_packet));
}

4 个答案:

答案 0 :(得分:2)

如果您使用memcpy(packet, tx_packet, sizeof(*tx_packet));,则将tx_Packet的内存表示复制到数据包中,从tx_packet->length开始。

此外,当mallocating tx_packet时,该大小应为sizeof(*packet)+sizeof(uint8_t)(数据包长度加长度字段)

再次将tx_packet复制回packet时,您正在写出packet的边界。

编辑:
我忘了提到,根据你的编译器内存对齐参数,你可以获得字段的任何长度(包括tx_packet->length)来加速内存操作。在32位机器上它可以是4并用垃圾填充。

答案 1 :(得分:2)

现在,您的create_tx_packet()函数将函数中创建的Tx_Packet结构复制到uint8_t数组。该结构包含数据的长度和指针,但不包含数据本身。实际上没有必要使用struct作为中间步骤,特别是对于这样一个简单的数据包,所以你可以这样做:

static void create_tx_packet(uint8_t *packet, uint8_t *src, int length)
{
  *packet = length; /* set (first) uint8_t pointed to by packet to the
                       length */
  memcpy(packet + 1, src, length);  /* copy length bytes from src to
                                       the 2nd and subsequent bytes of
                                       packet */
}

您仍然需要确保packet指向所有内容(它至少length + 1个字节)。由于上述版本不会动态分配任何内容,因此它还会修复原始内存泄漏(在退出之前应该已释放tx_packet->datatx_packet。)

-

如果你想使用结构,你可以(因为数据在最后)改变你的结构使用数组而不是data的指针 - 然后额外的空间超过了struct可以用于数据,并通过struct中的data数组进行访问。结构可能是:

typedef struct {
  uint8_t length;
  uint8_t data[];
} Tx_Packet;

并且函数变为(如果使用临时结构):

static void create_tx_packet(uint8_t *packet, uint8_t *src, int length)
{
  /* allocate the temporary struct, with extra space at the end for the
     data */
  Tx_Packet *tx_packet = malloc(sizeof(Tx_Packet)+length);

  /* fill the struct (set length, copy data from src) */
  tx_packet->length = length;
  memcpy(tx_packet->data, src, length);

  /* copy the struct and following data to the output array */
  memcpy(packet, tx_packet, sizeof(Tx_Packet) + length);

  /* and remember to free our temporary struct/data */
  free(tx_packet);
}

不是分配临时结构,而是还可以使用struct指针直接访问packet中的字节数组,避免额外的内存分配:

static void create_tx_packet(uint8_t *packet, uint8_t *src, int length)
{
  /* Set a Tx_Packet pointer to point at the output array */
  Tx_Packet *tx_packet = (Tx_Packet *)packet;

  /* Fill out the struct as before, but this time directly into the
     output array so we don't need to allocate and copy so much */
  tx_packet->length = length;
  memcpy(tx_packet->data, src, length);
}

答案 2 :(得分:0)

使用

序列化结构时
memcpy(packet, tx_packet, sizeof(*tx_packet));

您正在复制长度和指向数据的指针,而不是数据本身。您可能需要进行两次memcpy次调用:其中一次sizeof(uint8_t)要复制长度字段,另一次length要复制数据。

答案 3 :(得分:0)

这一行:

Tx_Packet *tx_packet = malloc(sizeof(*packet));

只为数据包标头分配一个字节,然后立即写下结束,导致未定义的行为。你可能意味着

Tx_Packet *tx_packet = malloc(sizeof(*tx_packet));