【问题标题】:What is a lifetime of a function return value?函数返回值的生命周期是多少?
【发布时间】:2023-03-24 11:13:01
【问题描述】:

我读到了函数调用之间的 return 值,
并尝试了以下代码 sn-p :

/* file structaddr.c */
#include <stdio.h>    
#define MSIZE 10

struct simple
{   
    char c_str[MSIZE];
};
struct simple xprint(void)
{
    struct simple ret = { "Morning !" };
    return ret;
}
int main(void)
{   
    printf("Good %s\n", xprint().c_str);    
    return 0;
}

代码编译后没有错误和警告。
使用 GCC 4.4.3 (Ubuntu 4.4.3-4ubuntu5.1)Visual C++ 编译器测试。

 gcc -m32 -std=c99 -Wall -o test  structaddr.c  
 cl -W3 -Zi -GS -TC -Fetest structaddr.c

输出:
早安!

我对结果有点困惑。
代码写对了吗?

我的问题:

  • 函数returnvalue(array from a struct 在上面的例子中),以及如何正确访问它们?

  • return 值的生命周期在哪里结束?

【问题讨论】:

  • 返回值是临时的。它在使用后被丢弃。如果不将其存储到变量中,则在您第一次引用后它就消失了。
  • @JoachimPileborg 是的,我知道了,然后删除了我在您的此评论之前的评论。 :)
  • @boleto 你为什么感到困惑?你还期待别的吗?
  • C 和 C++ 是不同的语言,您应该在一个问题中只指定其中一个或输入两个问题,每种语言一个,除非有理由相信答案在两种语言。

标签: c visual-c++ gcc gcc4


【解决方案1】:

在 C 中,示例中的临时变量的生命周期在 printf 表达式完成时结束:

  • 根据 C 2011 (N1570) 6.2.4 8,当包含它的完整表达式(或声明符)的评估结束时,临时的生命周期结束:“具有结构或联合类型的非左值表达式,其中结构或 union 包含具有数组类型的成员(递归地,包括所有包含的结构和联合的成员)指的是具有自动存储持续时间和 临时生命周期的对象。它的生命周期从计算表达式时开始,其初始值为表达式的值。当包含完整表达式或完整声明符的评估结束时,它的生命周期结束。”
  • 根据 6.8 4:“完整表达式是不属于另一个表达式或声明符的表达式。”根据 6.7.6 3:“完整的声明符是不属于另一个声明符的声明符。”
  • 因此,当printf 表达式完成时,您示例中临时变量的生命周期结束。

在 C++ 中,您的示例中的生命周期与 C 中的相同:

  • 根据 C++ 2010 (N3092) 12.2 3:“临时对象在评估完整表达式 (1.9) 的最后一步时被销毁,完整表达式 (1.9) 包含它们的创建点。”
  • 根据 12.2 4 和 5:“在两种情况下,临时对象在与完整表达式结尾不同的点被销毁。第一个上下文是调用默认构造函数来初始化数组元素时。如果构造函数有一个或多个默认参数,则在默认参数表达式中创建的每个临时变量的销毁都将在构造下一个数组元素(如果有)之前进行排序。” “第二个上下文是当一个引用绑定到一个临时的。引用绑定的临时对象或引用绑定的子对象的完整对象的临时对象在引用的生命周期内持续存在,除了:...”(为简洁起见,我省略了例外情况,因为它们不适用在这里。)
  • 因此您的示例在 C++ 中是相同的,临时对象在评估 printf 表达式的最后一步被销毁。

【讨论】:

  • 我一直看到的方式是返回的对象不会超过下一个序列点,这是由对printf的调用引起的。在函数调用之前不是对表达式进行评估吗?
  • @EricPostpischil,很好的解释!只是一个小问题——调用printf()函数时是否可以修改数组数据
  • @boleto 如果您询问是否存在导致相应参数指向的对象被写入的 printf 格式说明符,则存在。但是,函数的返回值不是可修改的左值,因此任何写入它的尝试都是未定义的行为。
  • @undefinedbehaviour:xprint 返回的表达式在调用xprint 之前无法计算,直到xprint 返回它才存在。它必须在调用printf 之前进行评估,但在C 抽象模型中,它会继续存在,直到printf 表达式完成。序列点与该生命周期无关,因为 C 标准关于生命周期何时结束的规则没有提及序列点。
  • @GrijeshChauhan:请注意,GCC 的默认值为 -std=gnu89。因此,您正在使用 C 语言的非标准变体测试程序,该变体已有近 25 年的历史。
【解决方案2】:

函数xprint返回一个结构的副本,编译器将这个副本存储在一个临时文件中,临时文件的生命周期是printf函数调用的持续时间。当printf 函数返回时,该临时对象被销毁。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-16
    • 2013-01-28
    • 2019-12-27
    • 2021-06-28
    • 2010-09-19
    相关资源
    最近更新 更多