如果我在其中保留一个指向值的指针,C 标准是否将函数的返回结构保留在堆栈上?

aga*_*anm 10 c language-lawyer

以这个有争议的代码为例。

struct X {
     int arr[1];
     float something_else;
};
    
struct X get_x(int first)
{
     struct X ret = { .arr = { first } };
     return ret;
}

int main(int argc, char **argv) {
    int *p = get_x(argc+50).arr;
    
    return *p;
}
Run Code Online (Sandbox Code Playgroud)

get_x返回一个struct X. 我只对它的成员感兴趣arr。如果我只想要arr……为什么要为整个结构创建一个局部变量?

但是..那个代码正确吗?

在显示的示例中,C 标准是否知道将 的返回值保留在get_x堆栈上,直到调用堆栈帧结束,因为我正在用指针窥视其中?

dbu*_*ush 16

你在做什么是标准不允许的。

从函数返回的 struct 具有临时生命周期,该生命周期在它所使用的表达式之外结束。因此,在p初始化之后,它指向一个生命周期已结束且其值变为indeterminate 的对象。然后尝试p在以下语句中取消引用(现在不确定)会触发未定义的行为

这记录在C 标准的第 6.2.4p8 节中:

具有结构或联合类型的非左值表达式,其中结构或联合包含具有数组类型的成员(递归地包括所有包含的结构和联合的成员),指的是具有自动存储持续时间和临时生命周期的对象 它的生命周期从表达式被计算时开始,它的初始值是表达式的值。
当包含完整表达式或完整声明符的计算结束时,它的生命周期结束。任何修改具有临时生命周期的对象的尝试都会导致未定义的行为。

终身的对象,什么时候在第6.2.4p2指定其使用寿命到期后,一个指向对象:

对象的生命周期是程序执行的一部分,在此期间保证为其保留存储空间。一个对象存在,有一个常量地址,并在其整个生命周期中保留其最后存储的值。 如果对象在其生命周期之外被引用,则行为未定义。 当指针指向(或刚刚过去)的对象到达其生命周期结束时,指针的值变得不确定

如果要将函数的返回值分配给 的实例struct X,则可以安全地访问该arr实例的成员。

  • @GabrielStaples 该临时的*生命周期*在它出现的表达式之后结束。因此,以下使用“*p”的语句取消引用指向不再存在的对象的指针。 (4认同)
  • 在我看来,结构体是按值返回的,这将其整个副本放入临时变量中,从而使OP的代码有效并受到标准的允许。这将使其他答案正确,而这个陈述(“你所做的事情是标准不允许的。”)是错误的。 (2认同)