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

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...

C++:多态机制详解

目录 一. 多态的概念 1.静态多态&#xff08;编译时多态&#xff09; 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1&#xff09;.协变 2&#xff09;.析构函数的重写 5.override 和 final关键字 1&#…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...