C 没有阵列的结构的生存期

C 没有阵列的结构的生存期,c,struct,scope,return,lifetime,C,Struct,Scope,Return,Lifetime,以这个代码为例: #include <stdio.h> struct S { int x; int y; }; struct S foo(int a, int b) { struct S s = { a, b }; return s; } int main() { int a; a = foo(2, 4).x; printf("%d\n", a); return 0; } #包括 结构S{intx;inty

以这个代码为例:

#include <stdio.h>

struct S { int x; int y; };

struct S foo(int a, int b) {
    struct S s = { a, b };
    return s;
}

int main() {
    int a;

    a = foo(2, 4).x;
    printf("%d\n", a);
    return 0;
}
#包括
结构S{intx;inty;};
结构S foo(内部a、内部b){
结构S={a,b};
返回s;
}
int main(){
INTA;
a=foo(2,4).x;
printf(“%d\n”,a);
返回0;
}
它按预期工作。我关心的是返回的struct对象的生存期。我知道标准讨论了包含数组的结构的临时生存期,但在本例中,结构中没有数组

所以我猜只要
foo()
结束,它的返回值就应该是死的,对吗?但显然我们仍然可以访问
x
成员。为什么?

调用
foo(2,4)
返回函数中变量
s
的副本

此返回(和临时)副本的生存期将持续到完整表达式的结尾,即赋值
a=foo(2,4).x

这意味着对
a
的赋值是在临时结构的生命周期结束之前完成的,这意味着您显示的代码是正确有效的

您可以在中阅读有关终身学习的更多信息,例如

“我知道标准中谈到了包含数组的结构的临时生存期,但在这种情况下,结构中没有数组。”

你是说这段话:

具有结构或联合类型的非左值表达式,其中结构或联合包含具有数组类型的成员(递归地包括所有包含的结构和联合的成员)指具有自动存储持续时间和临时生存期的对象。36)其生存期从表达式求值时开始,其初始值为表达式的值。当包含完整表达式的计算结束时,其生存期结束。任何使用临时生存期修改对象的尝试都会导致未定义的行为。具有临时生存期的对象的行为就好像是为了有效类型而使用其值的类型声明的一样。这样的对象不需要有唯一的地址

36)当访问数组成员时,隐式获取此类对象的地址

来源:ISO/IEC 9899:2018(C18),§6.2.4/8

临时生存期是在包含数组成员的结构和联合的上下文中显式创建的,因为通过名称访问数组成员会给您一个指向数组第一个元素的指针,该元素在C11中添加本段之前调用了早期C标准中未定义的行为

克里斯·多德解释得稍微好一点

因此,临时寿命(标准中的意思)与具有非数组成员的结构无关

“所以我猜只要
foo()
结束,它的返回值就应该是死的,对吗?”

否。
foo()
返回
struct S
对象的副本,而不是对本地
struct S
对象的引用。请注意,
foo()
的返回类型是
struct S
,而不是
struct S*
(指向
struct S
的指针)

“但显然我们仍然可以访问
x
成员。为什么?”

因为你把副本还给了打电话的人。您试图从C标准访问此副本的成员
x
,而不是
struct S
对象
S
内部的
foo()

4完整表达式是不属于另一个表达式的表达式 声明符的表达式或表达式。以下每一项都是完整的 表达式:不是复合文本一部分的初始值设定项; 表达式语句中的表达式;选择语句的控制表达式(if或switch);控制 while或do语句的表达;每个选项(可选) 声明的表达方式;返回中的(可选)表达式 陈述一个完整的评估之间有一个序列点 表达式和下一个完整表达式的求值 评估

临时对象的生存期在包含完整表达式的计算结束时结束

所以在这个表达式语句中

a = foo(2, 4).x;

结构类型的返回对象是活动的,其数据成员
x
的值被分配给变量
a
,该变量在main中声明并具有main的块范围。

foo
返回的结构只是一个值(也称为右值)。它不是对象,并且没有任何生存期

考虑一个函数
intfoo(void){return3;}
。这将返回一个
int
值3,并且我们不希望能够获取它的地址,如
printf(“%p”,(void*)&foo())。3只是计算机中使用的一个值,没有相关的存储

类似地,给定
struct S{int x,y;}
struct S foo(void){return(struct S){3,4};}
返回一个包含3和4的
struct S
值。尽管我们通常认为结构是内存的布局,但C标准将此返回值视为一个值。它是一个复合值,有多个部分,但它只是一个没有关联存储的值。它不是C模型中的对象

同样,给定
struct S{int x,y[1];}
struct S foo(void){return(struct S){3,{4};}
返回包含3的
struct S
值和包含4的数组。在这里,C标准把自己画成了一个角落。它希望支持从函数返回结构,但是,当您访问数组时,如在
foo().y[0]
中,当前在C 2018 6.3.2.1 3中的规则表示数组被转换为指向其第一个元素的指针。指针必须指向存储,因此必须指向某个对象。我想一个解决方案可能是说不能在这样的结构值中单独使用数组。(您可以通过将返回值复制到带有