没有数组的结构的生命周期

如何解决没有数组的结构的生命周期

使用此代码:

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

它按预期工作。我担心的是返回的struct对象的生存期。我知道有关包含数组的结构的临时生存期的标准讨论,但是在这种情况下,结构中没有数组。

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

解决方法

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

您的意思是本段:

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

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

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

临时寿命是在包含数组成员的结构和联合的上下文中明确发明的,因为自array to pointer decay起,通过其名称访问数组成员将为您提供第一个指针的指针数组的元素,在C11中添加此段之前,它会在较早的C标准中调用未定义的行为。

克里斯·多德(Chris Dodd)解释得更好here

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

所以我想foo()结束后,它的返回值应该是无效的,对吧?

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

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

因为您将副本退回给呼叫者。您尝试访问此副本的成员x,而不是struct S内部的s对象foo()

,

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

此返回的(和临时的)副本的生存期为完整表达式(即赋值a = foo(2,4).x)的末尾。

这意味着对a的分配是在临时结构的生存期结束之前完成的,这意味着您显示的代码是正确且有效的。

例如,您可以阅读有关寿命的更多信息。 this reference

,

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

考虑一个函数int foo(void) { return 3; }。这将返回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表示数组已转换为指向其第一个元素的指针。指针必须指向存储,因此必须有一些对象指向。我想一种解决方案可能是说您不能在这样的结构值中单独使用数组。 (您可以通过将返回值复制到struct S x = foo();中然后再使用x中来使用返回值。)但是,C委员会采用的解决方案是为此类结构定义临时寿命。在C 2018 6.2.4 8中,它们的定义仅针对包含数组成员的结构和联合定义了临时生存期。

但是,在您的代码中,这无关紧要。因为您的foo(2,4)返回一个值,所以您可以根据需要使用该值; foo(2,4).x之所以有效,是因为它接受值的x成员。无需担心任何对象的寿命,因为不涉及任何对象。

,

根据C标准

4 完整表达式是另一个表达式的一部分 表达式或声明符。以下每个都是完整的 表达式:不属于复合文字的初始化程序; 表达式语句中的表达式;选择语句的控制表达式(if或switch);控制 表达一阵子或做声明;每个(可选) for语句的表达式;返回中的(可选)表达式 声明。评估一个完整项目之间有一个顺序点 表达式和下一个完整表达式的评估 评估。

当包含完整表达式的求值结束时,临时对象的生存期结束。

因此在此表达式语句中

a = foo(2,4).x;

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-