如果我在其中保留一个指向值的指针,C标准是否将函数的返回结构保留在堆栈上?
以这个有争议的代码为例。
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;
}
get_x返回一个struct X. 我只对它的成员感兴趣arr。如果我只想要arr……为什么要为整个结构创建一个局部变量?
但是..那个代码正确吗?
在显示的示例中,C 标准是否知道将 的返回值保留在get_x堆栈上,直到调用堆栈帧结束,因为我正在用指针窥视其中?
回答
你在做什么是标准不允许的。
从函数返回的 struct 具有临时生命周期,该生命周期在它所使用的表达式之外结束。因此,在p初始化之后,它指向一个生命周期已结束且其值变为indeterminate 的对象。然后尝试p在以下语句中取消引用(现在不确定)会触发未定义的行为。
这记录在C 标准的第 6.2.4p8 节中:
具有结构或联合类型的非左值表达式,其中结构或联合包含具有数组类型的成员(递归地包括所有包含的结构和联合的成员),指的是具有自动存储持续时间和临时生命周期的对象
。它的生命周期从表达式被计算时开始,它的初始值是表达式的值。
当包含完整表达式或完整声明符的计算结束时,它的生命周期结束。任何修改具有临时生命周期的对象的尝试都会导致未定义的行为。
凡终身的对象,什么时候在第6.2.4p2指定其使用寿命到期后,一个指向对象:
对象的生命周期是程序执行的一部分,在此期间保证为其保留存储空间。一个对象存在,有一个常量地址,并在其整个生命周期中保留其最后存储的值。 如果对象在其生命周期之外被引用,则行为未定义。 当指针指向(或刚刚过去)的对象到达其生命周期结束时,指针的值变得不确定
如果要将函数的返回值分配给 的实例struct X,则可以安全地访问该arr实例的成员。
- @GabrielStaples The *lifetime* of that temporary ends after the expression in which it appears. So the following statement which uses `*p` is dereferencing a pointer to an object which no longer exists.
- It seems to me the struct is returned by value, which makes an entire copy of it into a temporary variable, making the OP's code valid and allowed by the standard. That would make the other answers right, and this statement ("What you're doing is not allowed by the standard.") wrong.
THE END
二维码