将缓冲区转换为结构指针

时间:2017-11-07 11:56:14

标签: c pointers struct

我有一个缓冲区,并希望将其转换为结构的指针:

#include <stdint.h>
#include <stdio.h>

struct __attribute__((packed)) req {
    uint8_t a;
    uint16_t b;
    uint8_t *c;
};


void f(uint8_t *Buf)
{
    struct req *r = (struct req *)Buf;

    printf("a: %02x\n", r->a);
    printf("b: %04x\n", r->b);
    printf("c: %02x\n", r->c[0]);

}

int main()
{
    uint8_t buf[] = {0x01, 0x02, 0x03, 0x04 };

    f(buf);

    return 0;
}

该示例不起作用,因为第4个字节不是地址,而是实际数据。我可以修理&#34;这通过手动设置指针:

r->c = &Buf[3];

有没有办法用演员表演这个?

3 个答案:

答案 0 :(得分:2)

  

有没有办法用演员表演这个?

不,原因有很多:

  • 正如您所说,字节流与结构不对应。最后一项不是指针。只有当您知道存储在目标位置的实际数据与目标变量的类型相同时,才可以使用强制转换。
  • 演员表调用未定义的行为,因为它违反了the strict aliasing rule。任何事情都可能发生。
  • 字节流中的各种数据似乎未对齐,根据系统的不同,这可能是也可能不是问题。

在这种情况下,您必须手动反序列化数据:

struct req r = { buf[0], 
                 (uint16_t)buf[1]<<8 | buf[2], // assumes big endian
                 &buf[3] };

在这里,我们注意到代码也依赖于endianess。因此,您必须知道此数据来自的系统/协议的字节顺序,以便正确地对其进行反序列化。

答案 1 :(得分:0)

有什么方法可以通过演员表吗?

是的,根据以下假设,是可能的:

  • 您需要注意结构对齐(特定于编译器):
    #pragma pack(push, 1) ... #pragma pack(pop)
    __attribute__((packed))

  • 您需要注意架构与缓冲区中字节之间的字节序(如果需要,请进行转换)

您可以做的是在结构中使用void* c而不是uint8_t* c,然后将void*强制转换为显式指针类型。

示例1:

#include <stdint.h>
#include <stdio.h>

#pragma pack(push, 1)
typedef struct {
    uint8_t a;
    uint16_t b;
    void* c;
} req;
#pragma pack(pop)

void f(uint8_t* Buf)
{
    req* r = (req*)Buf;
    printf("a: %02x\n", r->a);
    printf("b: %04x\n", r->b);
    printf("c: %02x\n", ((uint8_t*)&r->c)[0]);
}
int main()
{
    uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04 };
    f(buf);
    return 0;
}

输出:

a: 01
b: 0302
c: 04

示例2:

#include <stdint.h>
#include <stdio.h>

#pragma pack(push, 1)
typedef struct {
    uint8_t a;
    uint16_t b;
    void* c;
} req;

typedef struct {
    uint8_t cmd;
    uint16_t value;
} SubPacket;
#pragma pack(pop)

void f(uint8_t* Buf)
{
    req* r = (req*)Buf;

    printf("a: %02x\n", r->a);
    printf("b: %04x\n", r->b);

    SubPacket* sub_packet = (SubPacket*)&r->c;

    printf("cmd: %02x\n", sub_packet->cmd);
    printf("value: %04x\n", sub_packet->value);

}

int main()
{
    uint8_t buf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };

    f(buf);

    return 0;
}

输出:

a: 01
b: 0302
cmd: 04
value: 0605

答案 2 :(得分:-2)

#include <stdint.h>
#include <stdio.h>

struct __attribute__((packed)) req {
    uint8_t a;
    uint16_t b;
    uint8_t c[]; /* <--- Use this notation to be able to achieve this */
};


void f(uint8_t *Buf)
{
    struct req *r = (struct req *)Buf;

    printf("a: %02x\n", r->a);
    printf("b: %04x\n", r->b);
    printf("c: %02x\n", r->c[0]);

}

int main()
{
    uint8_t buf[] = {0x01, 0x02, 0x03, 0x04 };

    f(buf);

    return 0;
}

请看这里:How to include a dynamic array INSIDE a struct in C?