0

Given the below simple code, where you have process_payload is given a pointer to the payload portion of the packet, how do you access the header portion? Ideally the caller should simply give a pointer to full packet from beginning, but there are cases where you don't have the beginning of the message and need to work backwards to get to the header info. I guess this question becomes a understanding of walking through the memory layout of a struct.

The header computes to 8 bytes with sizeof operation. I assume Visual C++ compiler added 3 bytes padding to header. The difference between pptr and pptr->payload is decimal 80 (not sure why this value??) when doing ptr arith (pptr->payload - pptr). Setting ptr = (struct Packet*)(payload - 80) works but seems more a hack. I don't quite understand why subtracting sizeof(struct header) doesn't work.

Thanks for any help you can give.

struct Header
{
    unsigned char id;
    unsigned int size;
};

struct Packet
{
    struct Header header;
    unsigned char* payload;
};


void process_payload(unsigned char* payload);

int main()
{
    struct Packet* pptr = (struct Packet*)malloc(sizeof(struct Packet));
    pptr->payload = (unsigned char*)malloc(sizeof(unsigned char)*10);

    process_payload(pptr->payload);

    return 1;
}

// Function needs to work backwards to get to header info. 
void process_payload(unsigned char* payload)
{
    // If ptr is correctly setup, it will be able to access all the fields
    // visible in struct Packet and not simply payload part.
    struct Packet* ptr;

    // This does not work when intuitively it should?
    ptr = (struct Packet*)(payload - sizeof(struct Header));
 }
ashton71
  • 27
  • 6
  • Check the (non-standard) `container_of` macro, which you can see [here](http://stackoverflow.com/questions/21455365/c-pointer-arithmetic-without-object-of-structure/21455524#21455524) – Elias Van Ootegem Sep 11 '14 at 08:35
  • `pptr` in `main()` is rather pointless in this code. It seems to me you are trying (and not succeeding) to craft a [*flexible array member*](http://stackoverflow.com/questions/3047530/flexible-array-member-in-c-structure) for the actual payload. – WhozCraig Sep 11 '14 at 08:38
  • As WhozCraig said, you must be trying to do something : I cant see the point of not passing directly a `struct Packet *` to `process_payload()` – Rerito Sep 11 '14 at 08:41
  • you may want to initialize your struct after malloc or use calloc, in your snippet they are left uninitialized. – AndersK Sep 11 '14 at 08:42

1 Answers1

1

It's because in main you allocate two pointers, and pass the second pointer to the process_payload function. The two pointers are not related.

There are two ways of solving this problem, where both include a single allocation.

The first solution is to used so called flexible arrays, where you have an array member last in the structure without any size:

struct Packet
{
    struct Header header;
    unsigned char payload[];
};

To use it you make one allocation, with the size of the structure plus the size of the payload:

struct Packet *pptr = malloc(sizeof(struct Packet) + 10);

Now pptr->payload is handled like a normal pointer pointing to 10 unsigned characters.

Another solution, which is a mix of your current solution and the solution with flexible arrays, is to make one allocation and make the payload pointer to point to the correct place in the single allocated memory block:

struct Packet
{
    struct Header header;
    unsigned char *payload;
};

// ...

struct Packet *pptr = malloc(sizeof(struct Packet) + 10);
pptr->payload = (unsigned char *) ((char *) pptr + sizeof(struct Packet);

Note that in this case, to get the Packet structure from the payload pointer, you have to use sizeof(Packet) instead of only sizeof(Header).


Two things to note about the code above:

  1. I don't cast the result of malloc
  2. sizeof(char) (and also the size of unsigned char) is specified to always be one, so no need for sizeof
Community
  • 1
  • 1
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Thanks a lot for the answer. I've seen the flexible pointers before, but was never really sure about why that was. Now I see. Thanks for the notes as well. – ashton71 Sep 11 '14 at 14:47