当前位置: 首页 > news >正文

关于c++中mutable、const、volatile这三个关键字及对应c++与汇编示例源码

这哥三之间的关系是有趣的,不妨看看这个:

cv (const and volatile) type qualifiers - cppreference.com

mutable

permits modification of the class member declared mutable even if the containing object is declared const.

即便一个对象是const的,它内部的成员变量如果被mutable修饰,则此成员变量依旧可以被修改。

const

很常见,用途如其字面意义:别改变它"作用域"内的对象。

volatile

就如其含义:生性活泼,莫对其"作用域"下的对象指手画脚。这里着重说一下volatile。

volatile相关特性

        1. 易变性。所谓的易变性,在汇编层面反映出来,就是两条语句,下一条语句不会直接使用上一条语句对应的volatile变量的寄存器内容,而是重新从内存中读取。
特性。

        2. "不可优化"特性。volatile告诉编译器,不要对我这个变量进行各种激进的优化,甚至将变量直接消除,保证程序员写在代码中的指令,一定会被执行。
        3. "顺序性",能够保证volatile变量间的顺序性,编译器不会进行乱序优化。 C/C++ Volatile变量,与非Volatile变量之间的操作,是可能被编译器交换顺序的。C/C++ Volatile变量间的操作,是不会被编译器交换顺序的。哪怕将所有的变量全部都声明为volatile,哪怕杜绝了编译器的乱序优化,但是针对生成的汇编代码,CPU有可能仍旧会乱序执行指令,导致程序依赖的逻辑出错,volatile对此无能为力 针对这个多线程的应用,真正正确的做法,是构建一个happens-before语义(请见下面的内存顺序说明)。

特别注意的误区

volatile和多线程这种并行数据同步机制无关,也不能解决这类问题。相关问题请见:

内存顺序 std::memory_order - cppreference.com

const 和 volatile 关键字可更改处理指针的方式。 const 关键字指定指针在初始化后无法修改;此后指针将受到保护,防止进行修改。
volatile 关键字指定与后跟的名称关联的值可由用户应用程序中的操作以外的操作修改。 因此,volatile 关键字对于声明共享内存中可由多个进程访问的对象或用于与中断服务例程通信的全局数据区域很有用。
如果某个名称被声明为 volatile,则每当程序访问该名称时,编译器都会重新加载内存中的值。 这将显著减少可能的优化。 但是,当对象的状态可能意外更改时,这是保证可预见的程序性能的唯一方法。

如果将 struct 成员标记为 volatile,则 volatile 将传播到整个结构。 如果结构不具有可通过使用一个指令在当前体系结构上复制的长度,则此结构上可能完全丢失 volatile。

volatile 关键字失效

如果满足下列条件之一,则 volatile 关键字可能对字段不起作用:
        1. 可变字段的长度超过可使用一条指令在当前体系结构上复制的最大大小。
        2. 最外层包含 struct 的长度 - 或如果它是可能嵌套的 struct 的成员 - 超过可使用一条指令在当前体系结构上复制的最大大小。
尽管处理器不会对不可缓存的内存访问重新排序,但必须将不可缓存的变量标记为 volatile,从而保证此编译器不会对内存访问重新排序。
声明为 volatile 的对象不在某些优化中使用,因为它们的值可以随时更改。 系统在请求易失对象时始终读取该对象的当前值,即使前面的指令要求从同一对象获取值也是如此。 此外,对象的值会立即在赋值时写入。

volatile 原理源码示例

注:以下所有示例的c++源码一致,只区分是否使用volatile关键字

c++源程序:

#include <stdio.h>
int main(int argc, char** argv)
{auto sk = argc;int a = 11 << sk;int b = 19 + argc;int rv = a + b * 8;rv *= sk;return rv;
}

VS Debug环境MASM反汇编

没有使用volatile关键字修饰

反汇编代码:

00007FF7DE032993  mov         eax,dword ptr [argc]  
00007FF7DE032999  mov         dword ptr [sk],eax
00007FF7DE03299C  mov         eax,dword ptr [sk]  
00007FF7DE03299F  mov         ecx,0Bh  
00007FF7DE0329A4  mov         dword ptr [rbp+134h],ecx  
00007FF7DE0329AA  movzx       ecx,al  
00007FF7DE0329AD  mov         eax,dword ptr [rbp+134h]  
00007FF7DE0329B3  shl         eax,cl  
00007FF7DE0329B5  mov         dword ptr [a],eax
00007FF7DE0329B8  mov         eax,dword ptr [argc]  
00007FF7DE0329BE  add         eax,13h  
00007FF7DE0329C1  mov         dword ptr [b],eax
00007FF7DE0329C4  mov         eax,dword ptr [a]  
00007FF7DE0329C7  mov         ecx,dword ptr [b]  
00007FF7DE0329CA  lea         eax,[rax+rcx*8]  
00007FF7DE0329CD  mov         dword ptr [rv],eax
00007FF7DE0329D0  mov         eax,dword ptr [rv]  
00007FF7DE0329D3  imul        eax,dword ptr [sk]  
00007FF7DE0329D7  mov         dword ptr [rv],eax
00007FF7DE0329DA  mov         eax,dword ptr [rv]  
00007FF7DE0329DD  lea         rsp,[rbp+148h]  
00007FF7DE0329E4  pop         rdi  
00007FF7DE0329E5  pop         rbp  
00007FF7DE0329E6  ret

使用volatile关键字修饰

c++代码:

#include <stdio.h>
int main(int argc, char** argv)
{auto sk = argc;int a = 11 << sk;int b = 19 + argc;volatile int rv = a + b * 8;rv *= sk;return rv;
}

反汇编代码:

00007FF7F4102993  mov         eax,dword ptr [argc]  
00007FF7F4102999  mov         dword ptr [sk],eax
00007FF7F410299C  mov         eax,dword ptr [sk]  
00007FF7F410299F  mov         ecx,0Bh  
00007FF7F41029A4  mov         dword ptr [rbp+134h],ecx  
00007FF7F41029AA  movzx       ecx,al  
00007FF7F41029AD  mov         eax,dword ptr [rbp+134h]  
00007FF7F41029B3  shl         eax,cl  
00007FF7F41029B5  mov         dword ptr [a],eax
00007FF7F41029B8  mov         eax,dword ptr [argc]  
00007FF7F41029BE  add         eax,13h  
00007FF7F41029C1  mov         dword ptr [b],eax
00007FF7F41029C4  mov         eax,dword ptr [a]  
00007FF7F41029C7  mov         ecx,dword ptr [b]  
00007FF7F41029CA  lea         eax,[rax+rcx*8]  
00007FF7F41029CD  mov         dword ptr [rv],eax
00007FF7F41029D0  mov         eax,dword ptr [rv]  
00007FF7F41029D3  imul        eax,dword ptr [sk]  
00007FF7F41029D7  mov         dword ptr [rv],eax
00007FF7F41029DA  mov         eax,dword ptr [rv]
00007FF7F41029DD  lea         rsp,[rbp+148h]  
00007FF7F41029E4  pop         rdi  
00007FF7F41029E5  pop         rbp  
00007FF7F41029E6  ret

VS Release环境MASM反汇编

没有使用volatile关键字修饰

反汇编代码:

00007FF748801000  mov         eax,0Bh  
00007FF748801005  shl         eax,cl
00007FF748801007  lea         eax,[rax+rcx*8]  
00007FF74880100A  add         eax,98h
00007FF74880100F  imul        eax,ecx
00007FF748801012  ret

使用volatile关键字修饰

反汇编代码:

00007FF650C11005  shl         eax,cl
00007FF650C11007  lea         eax,[rax+rcx*8]  
00007FF650C1100A  add         eax,98h  
00007FF650C1100F  mov         dword ptr [rsp+8],eax
00007FF650C11013  mov         eax,dword ptr [rv]  
00007FF650C11017  imul        eax,ecx  
00007FF650C1101A  mov         dword ptr [rv],eax
00007FF650C1101E  mov         eax,dword ptr [rv]
00007FF650C11022  ret 

Linux GUN x86 64bit AT&T 环境优化参数O1反汇编

没有使用volatile关键字修饰

c++源码:

#include <stdio.h>
int main(int argc, char** argv)
{auto sk = argc;int a = 11 << sk;int b = 19 + argc;int rv = a + b * 8;rv *= sk;return rv;
}

反汇编代码:

0000 89F9     		movl	%edi, %ecx
0002 B80B0000 		movl	$11, %eax
0007 D3E0     		sall	%cl, %eax
0009 8D84F898 		leal	152(%rax,%rdi,8), %eax
0010 0FAFC7   		imull	%edi, %eax
0013 C3       		ret

使用volatile关键字修饰

c++源码:

#include <stdio.h>
int main(int argc, char** argv)
{auto sk = argc;int a = 11 << sk;int b = 19 + argc;volatile int rv = a + b * 8;rv *= sk;return rv;
}

反汇编代码:

0000 89F9     		movl	%edi, %ecx
0002 B80B0000 		movl	$11, %eax
0007 D3E0     		sall	%cl, %eax
0009 8D84F898 		leal	152(%rax,%rdi,8), %eax
0010 894424FC 		movl	%eax, -4(%rsp)
0014 8B4424FC 		movl	-4(%rsp), %eax
0018 0FAFC7   		imull	%edi, %eax
001b 894424FC 		movl	%eax, -4(%rsp)
001f 8B4424FC 		movl	-4(%rsp), %eax
0023 C3       		ret

总结:

        由上面的这些代码可以看到,非Debug环境有优化,但是因为volatile关键字的作用,有没有volatile关键字,优化后的汇编指令是不一样的。

关于Linux下AT&T格式汇编的详情请见: Linux c++反汇编源码细节解释说明_含影的博客-CSDN博客

如果使用GDB在Linux调试,GDB下载地址为: Index of /gnu/gdb

相关文章:

关于c++中mutable、const、volatile这三个关键字及对应c++与汇编示例源码

这哥三之间的关系是有趣的&#xff0c;不妨看看这个&#xff1a; cv (const and volatile) type qualifiers - cppreference.com mutable permits modification of the class member declared mutable even if the containing object is declared const. 即便一个对象是con…...

把大模型装进手机,分几步?

点击关注 文 | 姚 悦 编 | 王一粟 大模型“跑”进手机&#xff0c;AI的战火已经从“云端”烧至“移动终端”。 “进入AI时代&#xff0c;华为盘古大模型将会来助力鸿蒙生态。”8月4日&#xff0c;华为常务董事、终端BG CEO、智能汽车解决方案BU CEO 余承东介绍&#xff0c…...

c++游戏制作指南(三):c++剧情类文字游戏的制作

&#x1f37f;*★,*:.☆(&#xffe3;▽&#xffe3;)/$:*.★* &#x1f37f; &#x1f35f;欢迎来到静渊隐者的csdn博文&#xff0c;本文是c游戏制作指南的一部&#x1f35f; &#x1f355;更多文章请点击下方链接&#x1f355; &#x1f368; c游戏制作指南&#x1f3…...

Flutter系列文章-实战项目

在本篇文章中&#xff0c;我们将通过一个实际的 Flutter 应用来综合运用最近学到的知识&#xff0c;包括保存到数据库、进行 HTTP 请求等。我们将开发一个简单的天气应用&#xff0c;可以根据用户输入的城市名获取该城市的天气信息&#xff0c;并将用户查询的城市列表保存到本地…...

HCIA---TCP/UDP协议

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 目录 文章目录 一.UDP协议简介 UDP协议的特点&#xff1a; 二.TCP协议简介 TCP协议特点 三.TCP和UDP的区别 思维导图 一.UDP协议简介 UDP&#xff08;User …...

数据库索引的使用

1、MySQL的基本架构 架构图 左边的client可以看成是客户端&#xff0c;客户端有很多&#xff0c;像我们经常你使用的CMD黑窗口&#xff0c;像我们经常用于学习的WorkBench&#xff0c;像企业经常使用的Navicat工具&#xff0c;它们都是一个客户端。右边的这一大堆都可以看成是…...

校验 GPT-4 真实性的三个经典问题:快速区分 GPT-3.5 与 GPT-4,并提供免费测试网站

现在已经有很多 ChatGPT 的套壳网站&#xff0c;以下分享验明 GPT-4 真身的三个经典问题&#xff0c;帮助你快速区分套壳网站背后到底用的是 GPT-3.5 还是 GPT-4。 大家可以在这个网站测试&#xff1a;https://ai.hxkj.vip&#xff0c;免登录可以问三条&#xff0c;登录之后无限…...

SpringBoot整合MongoDB连接池(含源码)

&#x1f4a1;版本依赖 jdk 17 SpringBoot 3.1.0 Mongo 6.0.8 mybatis-plus 2.0.2 &#x1f4a1;环境准备 &#x1f335;MongoDB安装 安装教程请查看&#xff1a;一文搞定(linuxwindowsdocker)安装MongoDB &#x1f335;导入依赖 <parent><groupId>org.sp…...

[oeasy]python0082_[趣味拓展]控制序列_清屏_控制输出位置_2J

光标位置 回忆上次内容 上次了解了键盘演化的过程 ESC 从 组合键到 独立按键 ESC的作用 是 进入 控制序列配置 控制信息控制信息 \033[y;xH 设置光标位置\033[2J 清屏 这到底怎么控制&#xff1f;&#xff1f;&#xff1f;&#x1f914;谁来实现这些功能&#xff1f; 控制…...

Zookeeper+kafka

目录 1. Zookeeper定义 2. Zookeeper工作机制 3. Zookeeper特点 4. Zookeeper数据结构 5. Zookeeper应用场景 5.1 统一命名服务 5.2 统一配置管理 5.3 统一集群管理 5.4 服务器动态上下线 5.5 软负载均衡 6. Zookeeper 选举机制 6.1 第一次启动选举机制 6.2 非第一…...

Gpt微信小程序搭建的前后端流程 - 前端小程序部分-1.基础页面框架的静态设计(二)

Gpt微信小程序搭建的前后端流程 - 前端小程序部分-1.基础页面框架的静态设计(二) 在开始这个专栏&#xff0c;我们需要找一个小程序为参考&#xff0c;参考和仿照其界面&#xff0c;聊天交互模式。 这里参考小程序-小柠AI智能聊天&#xff0c;可自行先体验。 该小程序主要提供了…...

Flask进阶:构建RESTful API和数据库交互

在初级教程中&#xff0c;我们已经介绍了如何使用Flask构建基础的Web应用。在本篇中级教程中&#xff0c;我们将学习如何用Flask构建RESTful API&#xff0c;以及如何使用Flask-SQLAlchemy进行数据库操作。 一、构建RESTful API REST&#xff08;Representational State Tran…...

6.9(Java)二叉搜索树

1.我的代码: public class BinarySearchTree {class TreeNode {public int key;public TreeNode left;public TreeNode right;public TreeNode(int key) {this.key key;}}public TreeNode root; // 根节点// 插入一个元素,注意&#xff0c;不能插入重复的值&#xff0c;如…...

洛谷P2256 一中校运会之百米跑

题目背景 在一大堆秀恩爱的 ** 之中&#xff0c;来不及秀恩爱的苏大学神踏着坚定&#xff08;&#xff1f;&#xff09;的步伐走向了 100 100 100 米跑的起点。这时苏大学神发现&#xff0c;百米赛跑的参赛同学实在是太多了&#xff0c;连体育老师也忙不过来。这时体育老师发…...

python-opencv对极几何 StereoRectify

OpenCV如何正确使用stereoRectify函数 函数介绍 用于双目相机的立体校正环节中&#xff0c;这里只谈谈这个函数怎么使用&#xff0c;参数具体指哪些函数参数 随便去网上一搜或者看官方手册就能得到参数信息&#xff0c;但是&#xff01;&#xff01;相对关系非常容易出错&…...

pom文件---maven

027-Maven 命令行-实验四-生成 Web 工程-执行生成_ev_哔哩哔哩_bilibili 27节.后续补充 一.maven下载安装及配置 1)maven下载 2) settings文件配置本地仓库 3)settings配置远程仓库地址 4)配置maven工程的基础JDK版本 5)确认JDK环境变量配置没问题,配置maven的环境变量 验证…...

界面控件DevExpress.Drawing图形库早期增强功能分享

众所周知&#xff0c;DevExpress在v22.2发布周期中引入了全新的DevExpress.Drawing图形库&#xff08;并且已经在随后的小更新中引入了一系列增强功能&#xff09;。 在这篇博文中&#xff0c;我们将总结在DevExpress v23.1中解决的一些问题&#xff0c;以及在EAP构建中为以下…...

Semantic Kernel 入门系列:Connector连接器

当我们使用Native Function的时候&#xff0c;除了处理一些基本的逻辑操作之外&#xff0c;更多的还是需要进行外部数据源和服务的对接&#xff0c;要么是获取相关的数据&#xff0c;要么是保存输出结果。这一过程在Semantic Kernel中可以被归类为Connector。 Connector更像是…...

Maven介绍-下载-安装-使用-基础知识

Maven介绍-下载-安装-使用-基础知识 Maven的进阶高级用法可查看这篇文章&#xff1a; Maven分模块-继承-聚合-私服的高级用法 文章目录 Maven介绍-下载-安装-使用-基础知识01. Maven1.1 初识Maven1.1.1 什么是Maven1.1.2 Maven的作用 02. Maven概述2.1 Maven介绍2.2 Maven模型…...

Ansible环境搭建,CentOS 系列操作系统搭建Ansible集群环境

Ansible是一种自动化工具&#xff0c;基于Python写的&#xff0c;原理什么的就不过多再说了&#xff0c;详情参考&#xff1a;https://www.itwk.cc/post/403.html https://blog.csdn.net/qq_34185638/article/details/131079320?spm1001.2014.3001.5502 环境准备 HOSTNAMEIP…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

Spring Boot 实现流式响应(兼容 2.7.x)

在实际开发中&#xff0c;我们可能会遇到一些流式数据处理的场景&#xff0c;比如接收来自上游接口的 Server-Sent Events&#xff08;SSE&#xff09; 或 流式 JSON 内容&#xff0c;并将其原样中转给前端页面或客户端。这种情况下&#xff0c;传统的 RestTemplate 缓存机制会…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

DBAPI如何优雅的获取单条数据

API如何优雅的获取单条数据 案例一 对于查询类API&#xff0c;查询的是单条数据&#xff0c;比如根据主键ID查询用户信息&#xff0c;sql如下&#xff1a; select id, name, age from user where id #{id}API默认返回的数据格式是多条的&#xff0c;如下&#xff1a; {&qu…...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用

文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么&#xff1f;1.1.2 感知机的工作原理 1.2 感知机的简单应用&#xff1a;基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

【SpringBoot自动化部署】

SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一&#xff0c;能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时&#xff0c;需要添加Git仓库地址和凭证&#xff0c;设置构建触发器&#xff08;如GitHub…...