内存序学习笔记(一)——表达式求值顺序

你知道为什么 i = i++ + 2 在 C++17 前行为未定义吗?

你知道为什么 func(a(), b()) 中,a()b() 的执行顺序为什么不是确定的吗?

这篇文章可以解答你的疑惑。

注:内容中包含作者自行理解的表述,请谨慎参考。

表达式求值

每个表达式的求值包括:

  • 值计算:计算表达式所返回的值。
  • 引发副作用:访问(读或写)volatile 泛左值所指代的对象,修改(写入)对象,调用库 I/O 函数,或调用任何做出这些操作的函数。
表达式副作用
访问 volatile 对象可能将寄存器中的该变量值更新为内存中的值
修改对象除了对象被修改,程序的状态也有略微改变
I/O对外部环境产生影响
包括上述所有表达式的函数如上

例如,表达式 a++值计算指这个表达式的返回值是 a,引发副作用a 的值加了 1。但在这个例子中,副作用是已定义的,是用户期望的。

顺序

按顺序早于(sequenced before)

  • A 按顺序早于 B(等价地,B 按顺序晚于 A),则 A 的求值会在 B 的求值开始前完成。
  • A 不按顺序早于 B 而 B 不按顺序早于 A:
    • 无顺序(unsequenced),则它们以任何顺序进行,并且同线程内,编译器可以将两者 CPU 指令交错。
    • 顺序不确定(indeterminately sequenced),它们以任何顺序进行,但不可重叠。下次求值顺序可以相反。

注意无顺序顺序不确定的区别。由此推出,顺序不确定早于都属于已定义的顺序。只有无顺序是未定义的。

求值顺序规则

将在另一篇文章中说明以下相关知识点:完整表达式、弃值表达式、成分表达式(子表达式)、指名函数表达式、成员指针表达式、复合赋值表达式。

编号表达式类型操作(早于)对象
1完整表达式值计算、副作用下一个完整表达式
2运算符的操作数值计算运算符结果
3函数实参值计算、副作用函数体内任何语句
4(内建)后自增、后自减值计算副作用
5(内建)前自增、前自减副作用值计算
6&& || ,(逗号)的左操作数值计算、副作用右操作数
7与条件运算符(?:)第一表达式值计算、副作用第二、三表达式
8(内建)赋值运算符、复合赋值运算符的左右操作数值计算副作用(修改左操作数)
8.1(内建)赋值运算符、复合赋值运算符副作用(修改左操作数)值计算(返回引用之前)
9列表初始化的子句值计算、副作用其后的子句
10函数调用表达式中,指名函数表达式值计算、副作用 C++17起实参、默认形参
11下标表达式 E1[E2] 中,E1值计算、副作用 C++17起E2
12成员指针表达式 E1.*E2E1->*E2 中,E1值计算、副作用 C++17起E2
13移位运算符表达式 E1 << E2E1 >> E2 中,E1值计算、副作用 C++17起E2
14简单赋值表达式 E1 = E2 或复合赋值表达式 E1 @= E2 中,E2值计算、副作用 C++17起E1
  1. 如果一个函数调用和一个表达式(可以是另一个函数调用)没有明确顺序,二者的求值顺序不确定。(程序必须表现为如同一次函数调用的 CPU 指令,不会与其它表达式求值指令交错。C++17起std::execution::par_unseq 例外)
  2. new() 的调用相对于 new 表达式中各实参的求值,是顺序不确定的(C++17前);顺序早于它(C++17起)。
  3. 函数返回值的复制按顺序早于 return 语句 末尾处对所有临时量的销毁。后者又早于该块中所有局部变量的销毁。
    int add(int a, int b) {return a + b;
    }int main() {int c = add(1, 2);
    }`add()` 的结果复制到 `c` 早于 `a+b` 结果临时量的销毁
    后者又早于局部变量 `a,b` 的销毁
  4. C++17起 函数调用中,每个形参的值计算和副作用(二者作为一个整体)与其它任何形参相比是顺序不确定的。
  5. C++17起 重载的运算符遵循它所重载的内建运算符的定序规则。
  6. C++17起 列表初始化逗号分隔的每个表达式,如同函数调用一般求值(顺序不确定)。

未定义行为

注:切记未定义顺序顺序不确定的区别。

  • 如果某个内存位置上的一项副作用相对于同一个内存位置上的另一副作用是无顺序的,那么它的行为未定义。

例 1:

i = ++i + 2;  // OK

++i 副作用早于求值(第 5 条),等号右边的值计算早于左边副作用(赋值)(第 8 条)。执行顺序为:

++i 副作用 > ++i 求值 > ++i + 2 求值 > i = ++i + 2 副作用 > i = ++i + 2 求值。


例 2:

i = i++ + 2; // C++17 前行为未定义

C++17前,i++ 求值早于副作用(第 6 条),两边的值计算早于 i = i++ + 2 的副作用(第 8 条),而没有定义两个副作用的顺序,故而 i 值不确定,行为未定义。
C++17起,i++ 的副作用早于 i = i++ +2 的副作用(第 14 条)。因此可能(“可能”是因为i++2 的求值顺序是不确定的)的执行顺序为:

i++ 求值 > i++ + 2 求值 > i++ 副作用 > i = i++ + 2 副作用 > i = i++ + 2 求值


例 3:

f(i = -2, i = -2); // C++17 前行为未定义

C++17新增了一项规则(第 18 条),它规定了形参求值和副作用是顺序不确定的,此前未定义。此前两个 i = -2 不仅顺序不一定,甚至 CPU 指令可能交错。此后尽管顺序不确定,但 CPU 指令不会交错。因此执行顺序总是:

i = -2 副作用 > i = -2 求值 > i = -2 副作用 > i = -2 求值 > f(i = -2, i = -2) 副作用 > f(i = -2, i = -2) 求值


例 4:

f(++i, ++i);       // C++17 前行为未定义,C++17 起未指明

同上,C++17前,++i++i 的副作用顺序是未定义的。C++17后(第 18 条),不管编译器优先执行哪个 ++i 都是符合规则的。但由于两个 ++i 顺序不确定,所以该表达式的值计算和副作用未明确。


例 5:

i = ++i + i++;     // 行为未定义

同例 2,i++i = ++i + i ++ 的副作用顺序未定义。

序列点规则(C++11前)

C++11 前没有 C++11起一般完备的规则,表达式求值的顺序规定依靠序列点定义。

C++11前的定义

序列点 (sequence point)是执行序列中的点,在该点所有来自序列中先前求值的副作用都已经完成,而后继求值的副作用都尚未开始。

C++11前的规则

  1. 每个完整表达式结尾(典型地在分号处)有一个序列点。

  2. 调用函数时(无论该函数是否内联,无论是否使用函数调用语法),所有函数实参的求值(若存在)之后有一个序列点,它发生于函数体内的任何表达式或语句的执行之前。

  3. 在从函数返回时,在从函数调用结果的复制初始化之后,和 return 语句的 表达式 末尾的临时对象析构(若存在)前,有一个序列点。

  4. 对函数的返回值进行复制之后,并在函数外任何表达式的执行之前有一个序列点。

  5. 一旦函数执行开始,则在被调用函数的执行完成前,不求值调用方函数的任何表达式(函数不能交错执行)。

  6. 每个使用内建(非重载)运算符的下列四种表达式的求值中,表达式 a 的求值后有一个序列点。

a && b
a || b
a ? b : c
a , b

C++11前的未定义行为

  1. 前后序列点间,至多可以修改在同一个内存位置中的任何对象的存储值一次,否则行为未定义。
i = ++i + i++;     // 未定义行为
i = i++ + 1;       // 未定义行为
i = ++i + 1;       // 未定义行为
++ ++i;            // 未定义行为
f(++i, ++i);       // 未定义行为
f(i = -1, i = -1); // 未定义行为
  1. 前后序列点间,访问表达式求值所修改的在同一个内存位置中的任何对象的先前值,必须只为确定要存储的值。如果以其他任何方式访问,那么行为未定义。
cout << i << i++; // 未定义行为
a[i] = i++;       // 未定义行为

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/878773.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分享一套外链系统,付费进群系统

本系统特点&#xff0c;活码系统以及卡片系统&#xff0c;付费进群系统 分享一套外链系统其中带付费进群系统插件&#xff0c;前端做了美化

第90集《大佛顶首楞严经》

《大佛顶如来密因修正了义诸菩萨万行首楞严经》。监院法师慈悲&#xff0c;诸位法师&#xff0c;诸位同学&#xff0c;阿弥陀佛&#xff01; 请大家打开讲义197面 子一、现化表法 诵持『楞严神咒』在整个修学《首楞严王三昧》的过程&#xff0c;它所扮演的角色有两个&#x…

记录一下idea的一些使用技巧和遇到的异常(持续更新)

技巧 自己的模板——live template 有些代码在项目中通常会被用到或会被重复使用&#xff0c;可以自己写一个模板存起来&#xff0c;要用的时候用快捷键生成就可以了。 在这里选择生效范围 现在&#xff0c;就有我们自己的模板了&#xff0c;一回车就自动生成 idea的全局配置…

蓄水池漂浮物识别摄像机

蓄水池是重要的水资源储备设施&#xff0c;但常常会受到漂浮物的影响&#xff0c;影响水质和使用效果。为了及时监测和清理蓄水池中的漂浮物&#xff0c;蓄水池漂浮物识别摄像机 被广泛应用于各类水库、湖泊等场所。这种摄像机结合了图像识别技术和人工智能算法&#xff0c;能够…

照片信息的读取与分类(1)

通过Python的各种模块我们可以很方便的获取到文件的各种属性数据&#xff0c;比如文件修改时间、文件大小或是本节课获取到的照片拍摄时间等。获取到了这些数据后&#xff0c;我们就可以对文件按照需求进行移动、改名甚至删除等操作。配合Python批量处理文件的优势&#xff0c;…

elementUI table 给表头添加气泡显示(鼠标悬浮显示注释)

elementUI table 给表头添加气泡显示&#xff08;鼠标悬浮显示注释&#xff09; 前言&#xff1a;文档显示&#xff1a;&#xff08;使用插槽&#xff0c;我看看到底是怎么个事儿&#xff09;文档代码:修改后的效果&#xff1a;页面效果&#xff1a; 前言&#xff1a; 公司出现…

【ACM出版】2024年第四届工商管理与数据科学国际学术会议 (BADS 2024,10月25-27)

2024年第四届工商管理与数据科学国际学术会议(BADS 2024)将于2024年10月25-27日在中国重庆召开&#xff0c;大会由喀什大学支持。 在当今全球化与数字化迅速发展的时代&#xff0c;工商管理与数据科学作为推动经济增长和技术进步的重要力量&#xff0c;正以前所未有的速度交叉融…

骨传导耳机哪款好?精选五款热门骨传导耳机分享让你避免踩雷

目前在市面当中&#xff0c;骨传导耳机被称之为是黑科技耳机&#xff0c;骨传导耳机拥有很多优势&#xff0c;在听歌时不需要入耳&#xff0c;不会伤耳朵。随着骨传导耳机品牌的不断发展&#xff0c;人们在选购骨传导耳机时&#xff0c;也会觉得非常困难&#xff0c;可能一不小…

【知识图谱】4、LLM大模型结合neo4j图数据库实现AI问答的功能

昨天写了一篇文章&#xff0c;使用fastapi直接操作neo4j图数据库插入数据的例子&#xff0c; 本文实现LLM大模型结合neo4j图数据库实现AI问答功能。 废话不多说&#xff0c;先上代码 import gradio as gr from fastapi import FastAPI, HTTPException, Request from pydantic…

STM32CubeMX软件配置及点灯操作(基于STM32F4系列+HAL库)

注:本文主要记录一下STM32CubeMX软件的使用流程。 01 软件安装 1.keil 需要安装以下支持包(keil在线安装里没有对应芯片支持包)。 2.STM32CubeMX 安装库&#xff1a; 3.串口助手 02 硬件连接 该原理图来源于学益得在线课堂教学项目《RTOS项目实战&#xff1a;从PCB到Free…

STM32F407ZGT6单片机HAL库——DAC输出

一、输出直流电压 1.cubemax的配置&#xff08;通道1&#xff09; 2.直流电压大小计算 3.主函数加入初始化的程序 float DAC_voltage1.5;HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, DAC_voltage*4095/3.3);//HAL_DAC_Start(&hdac,DAC_CHANNEL_1); 二、…

(一)模式识别——基于SVM的道路分割实验(附资源)

写在前面&#xff1a;本报告所有代码公开在附带资源中&#xff0c;无法下载代码资源的伙伴私信留下邮箱&#xff0c;小编24小时内回复 一、实验目的 1、实验目标 学习掌握SVM&#xff08;Support Vector Machine&#xff09;算法思想&#xff0c;利用MATLAB的特定工具箱和库函…

【2024高教社杯全国大学生数学建模竞赛】ABCDEF题 问题分析、模型建立、参考文献及实现代码

【2024高教社杯全国大学生数学建模竞赛】ABCDEF题 问题分析、模型建立、参考文献及实现代码 1 比赛时间 北京时间&#xff1a;2024年9月5日 18:00-2024年9月8日20:00 2 思路内容 2.1 往届比赛资料 【2022高教社杯数学建模】C题&#xff1a;古代玻璃制品的成分分析与鉴别方案…

AI学习记录 - 旋转位置编码

创作不易&#xff0c;有用点赞&#xff0c;写作有利于锻炼一门新的技能&#xff0c;有很大一部分是我自己总结的新视角 1、前置条件&#xff1a;要理解旋转位置编码前&#xff0c;要熟悉自注意力机制&#xff0c;否则很难看得懂&#xff0c;在我的系列文章中有对自注意力机制的…

OpenFeign请求拦截器,注入配置属性类(@ConfigurationProperties),添加配置文件(yml)中的token到请求头

一、需求 OpenFeign请求拦截器&#xff0c;注入配置属性类&#xff08;ConfigurationProperties&#xff09;&#xff0c;添加配置文件&#xff08;yml&#xff09;中的token到请求头 在使用Spring Boot结合OpenFeign进行微服务间调用时&#xff0c;需要在发起HTTP请求时添加一…

MLLM(二)| 阿里开源视频理解大模型:Qwen2-VL

2024年8月29日&#xff0c;阿里发布了 Qwen2-VL&#xff01;Qwen2-VL 是基于 Qwen2 的最新视觉语言大模型。与 Qwen-VL 相比&#xff0c;Qwen2-VL 具有以下能力&#xff1a; SoTA对各种分辨率和比例的图像的理解&#xff1a;Qwen2-VL在视觉理解基准上达到了最先进的性能&#…

Apache Guacamole 安装及配置VNC远程桌面控制

文章目录 官网简介支持多种协议无插件浏览器访问配置和管理应用场景 Podman 部署 Apache Guacamole拉取 docker 镜像docker-compose.yml部署 PostgreSQL生成 initdb.sql 脚本部署 guacamole Guacamole 基本用法配置 VNC 连接 Mac 电脑开启自带的 VNC 服务 官网 https://guacam…

Gmtracker安装中存在的问题

Gmtracker安装中存在的问题 GMtracker安装问题该如何解决&#xff1f; 使用用服务器&#xff0c;在云服务器中使用conda环境 python 3.6的版本环境. pip install -r requirements.txt 在网上查找资料&#xff1a;opencv安装失败卡在这里是因为没有使用高版本的python环境 切换…

pdf在线转换成word免费版,一键免费转换

在日常的学习和办公中&#xff0c;PDF文件和Word文档是我们离不开的两种最常见的文件&#xff0c;而PDF与Word文档之间的转换成为了我们日常工作中不可或缺的一部分。无论是为了编辑、修改还是共享文件&#xff0c;掌握多种PDF转Word的方法都显得尤为重要。很多小伙伴关心能不能…

SpringSecurity Oauth2 - 密码模式完成身份认证获取令牌 [自定义UserDetailsService]

文章目录 1. 授权服务器2. 授权类型1. Password (密码模式)2. Refresh Token&#xff08;刷新令牌&#xff09;3. Client Credentials&#xff08;客户端凭证模式&#xff09; 3. AuthorizationServerConfigurerAdapter4. 自定义 TokenStore 管理令牌1. TokenStore 的作用2. Cu…