当前位置: 首页 > 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…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

Web后端基础(基础知识)

BS架构&#xff1a;Browser/Server&#xff0c;浏览器/服务器架构模式。客户端只需要浏览器&#xff0c;应用程序的逻辑和数据都存储在服务端。 优点&#xff1a;维护方便缺点&#xff1a;体验一般 CS架构&#xff1a;Client/Server&#xff0c;客户端/服务器架构模式。需要单独…...

WPF八大法则:告别模态窗口卡顿

⚙️ 核心问题&#xff1a;阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程&#xff0c;导致后续逻辑无法执行&#xff1a; var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题&#xff1a…...

海云安高敏捷信创白盒SCAP入选《中国网络安全细分领域产品名录》

近日&#xff0c;嘶吼安全产业研究院发布《中国网络安全细分领域产品名录》&#xff0c;海云安高敏捷信创白盒&#xff08;SCAP&#xff09;成功入选软件供应链安全领域产品名录。 在数字化转型加速的今天&#xff0c;网络安全已成为企业生存与发展的核心基石&#xff0c;为了解…...