返回带有指向内部结构数组的指针成员的结构是否安全?

时间:2019-08-08 08:15:02

标签: c

如果我们在结构体中有指向该结构体其他成员的指针,是否可以保证如果我们从函数返回结构体时,这些指针仍将指向该结构体的内部成员?

例如,这个经过小型优化的缓冲区结构:

#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;
}

当我在本地编译此代码并运行它时,它返回0,因此buffer.begin仍指向buffer.sso的开头。但是,是否可以保证总是这样?还是取决于编译器特定的RVO行为?

2 个答案:

答案 0 :(得分:3)

不。函数返回时,buffertest()后面的内存将不再存在。函数返回后,指向此buffer以及指向该buffer中任何成员的所有指针均无效。

以下是有效的替代方法:

#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;
}

答案 1 :(得分:0)

它不起作用,因为分配了局部变量buffer的内存超出范围,但是指针仍指向该区域。在main()中分配的buffer将具有不同的地址。该结构的内容是从函数中复制的,因此您必须更新指针。

一个高级版本是不使用指针,但使用数组索引的版本:

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

您可以安全地从函数中返回该代码,并且一切仍然有效。