Daan De Meyer
Daan De Meyer

Reputation: 13

Is it safe to return a struct with pointer members that point to internal struct arrays?

If we have pointers in a struct that point to other members of the struct, is it guaranteed these pointers will still point to the internal member of the struct if we return the struct from a function?

Take for example this small-size-optimized buffer struct:

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

struct buffer {
    uint8_t *begin;
    uint8_t *end;
    uint8_t sso[20];
};

struct buffer test() {
    struct buffer buffer;
    buffer.begin = buffer.sso;
    buffer.end = buffer.begin + 20;

    return buffer;
}

int main(void) {
  struct buffer buffer = test();

  return buffer.begin == buffer.sso ? 0 : 1;
}

When I compile this code locally and run it, it returns 0 so buffer.begin still points to the start of buffer.sso. However, is this guaranteed to always be case or am I depending on compiler-specific RVO behaviour?

Upvotes: 1

Views: 74

Answers (2)

Lundin
Lundin

Reputation: 214505

It won't work because the memory where the local variable buffer is allocated goes out of scope, but the pointers will still point at that area. The buffer allocated in main() will have a different address. The contents of that struct is copied from the function, so you would have to update the pointers.

One superior version is one that does not use pointers, but array indices:

struct buffer {
    size_t  begin;
    size_t  end;
    uint8_t sso[20];
};

struct buffer test() {
    struct buffer buffer;
    buffer.begin = 0;
    buffer.end = 20;
    return buffer;
}

This one you can safely return from the function and everything would be valid still.

Upvotes: 0

KamilCuk
KamilCuk

Reputation: 141583

No. The memory behind buffer inside test() functions stops existing when the function returns. All the pointers to this buffer and to any member inside that buffer are invalid after the function returns.

The following would be a valid alternative:

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

struct buffer {
    uint8_t *begin;
    uint8_t *end;
    uint8_t sso[20];
};

void buffer_init(struct buffer *buffer) {
    buffer->begin = buffer->sso;
    buffer->end = buffer->begin + 20;
}

int main(void) {
    struct buffer buffer;
    buffer_init(&buffer);

    return buffer.begin == buffer.sso ? 0 : 1;
}

Upvotes: 3

Related Questions