C 返回指针成员指向内部结构数组的结构安全吗?

C 返回指针成员指向内部结构数组的结构安全吗?,c,C,如果我们在结构中有指向该结构的其他成员的指针,那么如果我们从函数返回该结构,是否可以保证这些指针仍然指向该结构的内部成员 以这个小尺寸优化缓冲区结构为例: #include <stdint.h> #include <stdio.h> struct buffer { uint8_t *begin; uint8_t *end; uint8_t sso[20]; }; struct buffer test() { struct buffer

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

以这个小尺寸优化缓冲区结构为例:

#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;
}
#包括
#包括
结构缓冲区{
uint8_t*开始;
uint8_t*结束;
uint8_t sso[20];
};
结构缓冲区测试(){
结构缓冲区;
buffer.begin=buffer.sso;
buffer.end=buffer.begin+20;
返回缓冲区;
}
内部主(空){
结构缓冲区=测试();
return buffer.begin==buffer.sso?0:1;
}

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

否。当函数返回时,
缓冲区
内部
test()
函数中的内存停止存在。函数返回后,指向此
缓冲区
和该
缓冲区内任何成员的所有指针都无效

以下是有效的替代方案:

#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;
}
#包括
#包括
结构缓冲区{
uint8_t*开始;
uint8_t*结束;
uint8_t sso[20];
};
void buffer_init(结构缓冲区*缓冲区){
缓冲区->开始=缓冲区->单点登录;
缓冲区->结束=缓冲区->开始+20;
}
内部主(空){
结构缓冲区;
缓冲区初始化(&buffer);
return buffer.begin==buffer.sso?0:1;
}

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

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

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

您可以安全地从函数返回此函数,所有内容仍然有效。

我的测试返回1。这需要两个
结构
在内存中位于同一位置。如果添加
struct buffer2=buffer您希望地址神奇地改变吗?内存不会停止存在。对象的生命周期结束。标识符具有作用域。内存没有作用域,因此不能超出作用域。局部对象的生存期在其关联块的执行结束时结束(而不仅仅是在执行超出其范围时,如调用子例程时)。这一点很重要,因为指向此类对象的指针即使在直接或间接调用的子例程的完全不同范围内执行时也是有效的。