分析各种表达式求值过程
目录
算术运算与赋值
编译器常用的两种优化方案
常量传播
常量折叠
加法
Debug编译选项组下编译后的汇编代码分析
Release开启02执行效率优先
减法
Release版下优化和加法一致,不再赘述
乘法
除法
算术结果溢出
自增和自减
关系运算与逻辑运算
JCC指令
位运算
算术运算与赋值
算术运算包括加法、减法、乘法和除法,也称为四则运算。
赋值运算类似于数学中的“等于”,是将一个内存空间中的数据传递到另一个内存空间。因为内存没有处理器那样的控制能力,所以各个内存单元之间是无法直接传递数据的,必须通过处理器访问并中转,以实现两个内存单元之间的数据传输。
编译器常用的两种优化方案
在编译过程中,编译器常常会采用“常量传播”和“常量折叠”的方案对代码中的变量与常量进行优化
常量传播
将编译期间可计算出结果的变量转换成常量,这样就减少了变量的使用
常量折叠
当出现多个常量进行计算,且编译器可以在编译期间计算出结果时,源码中所有的常量计算都将被计算结果代替
如果在程序的逻辑中,声明的变量没有被修改过,而且上下文中不存在针对此变量的取地址和间接访问操作,那么这个变量就等价于常量,编译器就认为可以删除这个变量,直接用常量代替。使用常量的好处是可以生成立即数寻址的目标代码,常量作为立即数成为指令的一部分,从而减少了内存的访问次数。
加法
加法运算对应的汇编指令为ADD。在执行加法运算时,不同的操作数对应的转换指令不同,编译器会根据优化方式选择最佳的匹配方案。在编译器中常用的优化方案有如下两种。
- 生成文件占用空间最少。
- 执行效率最快。
在VS中,Release编译选项组的默认选项为02选项——执行效率最快。在Debug编译选项组中,使用的是Od+ZI选项,此选项使编译器产生的一切代码都以便于调试为根本前提,甚至为了便于单步跟踪以及源码和目标代码块的对应阅读,不惜增加冗余代码。当然也不是完全放弃优化,在不影响调试的前提下,会尽可能地进行优化。
Debug编译选项组下编译后的汇编代码分析
源码
#include<stdio.h>int main()
{int n1 = 0;int n2 = 0;// 变量+常量n1 = n1 + 1;// 常量+常量n1 = 1 + 2;// 变量+变量n1 = n1 + n2;printf("n1=%d\n", n1);return 0;
}
反汇编分析
归纳:
- 两个常量相加:编译期间就会计算出结构
- 有变量参与:变量取值存入寄存器相加后通过寄存器存入变量
Release开启02执行效率优先
开启02选项后,编译出来的汇编代码会有较大的变化。由于效率优先,编译器会将无用代码去除,并对可合并代码进行归并处理。
例如在代码清单4-1中,“n1 = n1 + 1;”这样的代码将被删除,因为在其后又重新对变量n1进行了赋值操作,而在此之前没有对变量n1做任何访问,所以编译器判定此句代码是可被删除的。
减法
计算机中,减法是通过加法实现的,减正等于加负,负数可以使用反码来代替;
源码
#include<stdio.h>int main(int argc, char* argv[])
{int n1 = argc;int n1;int n2 = 0;scanf("%d", &n2);n1 = n1 - 100;n1 = n1 + 5 - n2;printf("n1 = %d \r\n", n1);return 0;
}
反汇编
Release版下优化和加法一致,不再赘述
乘法
乘法运算对应的汇编指令分为有符号imul和无符号mul两种。由于乘法指令的执行周期较长,在编译过程中,编译器会先尝试将乘法转换成加法,或使用移位等周期较短的指令。当它们都不可转换时,才会使用乘法指令。
源码
#include<stdio.h>int main(int argc, char* argv[])
{int n1 = argc;int n2 = argc;// 变量乘常量printf("n1 * 15 = %d\n", n1 * 15);// 变量乘常量(2的幂)printf("n1 * 16 = %d\n", n1 * 16);// 两个常量相乘printf("2 * 2 = %d\n", 2 * 2);printf("n2 * 4 + 5 = %d\n", n2 * 4 + 5);// 混合运算printf("n1 * n2 = %d\n", n1 * n2);// 两变量相乘return 0;
}
反汇编
有符号数乘以常量值,且这个常量非2的幂,会直接使用有符号乘法imul指令或者左移加减运算进行优化。
当常量值为2的幂时,编译器会采用执行周期短的左移运算代替执行周期长的乘法指令。由于任何十进制数都可以转换成二进制数表示,在二进制数中乘以2就等同于所有位依次向左移动1位。
乘法运算与加法运算的结合编译器采用LEA指令处理。LEA语句的目的并不是获取地址。
除了两个未知变量的相乘无法优化外,其他形式的乘法运算都可以进行优化处理。如果运算表达式中有一个常量值,则此时编译器会首先匹配各类优化方案,最后对不符合优化方案的运算进行调整。
无符号乘法的原理与之相同
除法
除法运算对应的汇编指令分为有符号idiv和无符号div两种。除法指令的执行周期较长,效率也较低,所以编译器会想尽办法用其他运算指令代替除法指令。C++中的除法和数学中的除法不同,在C++中,除法运算不保留余数,有专门求取余数的运算(运算符为%),也称之为取模运算。对于整数除法,C++的规则是仅保留整数部分,小数部分完全舍弃。
编译器在除法的优化涉及到高深的数学知识,暂且放放
算术结果溢出
当数据大小超过存储空间时,就会发生溢出,溢出的数据不会保留;
进位:无符号数超出存储范围叫作进位。因为没有符号位,不会破坏数据,而进位的1位数据会被进位标志为CF保存。而在标志位CF中,可通过查看进位标志位CF,检查数据是否进位
溢出:有符号数超出存储范围叫作溢出,由于数据进位,从而破坏了有符号数的最高位——符号位。只有有符号数才有符号位,所以溢出只针对有符号数。可查看溢出标志位OF,检查数据是否溢出。OF的判定规则很简单,如果参与加法计算的数值符号一致,而计算结果符号不同,则判定OF成立,其他都不成立。
自增和自减
C++中使用“++”“--”来实现自增和自减操作。自增和自减有两种定义:
- 一种为自增自减运算符在语句块之后,则先执行语句块,再执行自增自减;
- 另一种恰恰相反,自增自减运算符在语句块之前,则先执行自增和自减,再执行语句块。
- 通常,自增和自减是被拆分成两条汇编指令语句执行的
源码
#include<stdio.h>int main(int argc, char* argv[])
{int n1 = argc;int n2 = argc;n2 = 5 + (n1++);n2 = 5 + (++n1);n1 = 5 + (n2--);n1 = 5 + (--n2);return 0;
}
反汇编
先将自增自减运算进行分离,然后根据运算符的位置来决定执行顺序 。 将 原 语 句 块 “n1=5+
(n1++);”分解为“n2=5+n1;”和“n1=n1+1”,这样就实现了先参与语句块运算,再自增1。同理,前缀++的拆分过程只是执行顺序做了替换,先将自身加1,再参与表达式运算。在识别过程中,后缀++必然会保存计算前的变量值,在表达式计算完成后,才取出之前的值加1,这是个显著特点。
关系运算与逻辑运算
- 或:比较运算符||左右的语句的结果,如果有一个值为真,则返回真值;如果都为假,则返回假值。
- 与:比较运算符&&左右的语句的结果,如果有一个值为假,则返回假
- 值;如果都为真值,则返回真值。
- 非:改变运算符!后面语句的真假结果,如果该语句的结果为真值,则返回假值;如果为假值,则返回真值。
JCC指令
通常情况下,这些条件跳转指令都与CMP和TEST匹配出现,但条件跳转指令检查的是标记位。因此,在有修改标记位的代码处,也可以根据需要使用条件跳转指令修改程序流程。
位运算
二进制数据的运算称为位运算,位运算操作符如下:
- “<<”:左移运算,最高位左移到CF中,最低位零
- “>>”:右移运算,最高位不变,最低位右移到CF中。
- “|”:位或运算,在两个数的相同位上,只要有一个为1,则结果 为1。
- “&”:位与运算,在两个数的相同位上,只有同时为1时,结果才 为1。
- “^”:异或运算,在两个数的相同位上,当两个值相同时为0,不同时为1。
- “~”:取反运算,将操作数每一位上的1变0,0变1。
有待提升之处:
1. JCC指令,位运算的反汇编指令不够熟练
2.除法的优化原理涉及复杂的数学知识,还没了解
相关文章:

分析各种表达式求值过程
目录 算术运算与赋值 编译器常用的两种优化方案 常量传播 常量折叠 加法 Debug编译选项组下编译后的汇编代码分析 Release开启02执行效率优先 减法 Release版下优化和加法一致,不再赘述 乘法 除法 算术结果溢出 自增和自减 关系运算与逻辑运算 JCC指…...

企业风险管理策略终极指南
企业风险管理不一定是可怕的。企业风险管理是一个模糊且难以定义的主题领域。它涵盖了企业的多种风险和程序,与传统的风险管理有很大不同。 那么,企业风险管理到底是什么?在本文中,我们将确定它是什么,提出两种常见的…...

OpenCV之分水岭算法(watershed)
Opencv 中 watershed函数原型: void watershed( InputArray image, InputOutputArray markers ); 第一个参数 image,必须是一个8bit 3通道彩色图像矩阵序列,第一个参数没什么要说的。关键是第二个参数 markers,Opencv官方文档的说…...
npm 命令
目录 初始化 搜索 安装 删除 更新 换源 查看 其他 补充 1.初始化 npm init #初始化一个package.json文件 npm init -y | npm init --yes 2.搜索 npm s jquery | npm search jquery 3.安装 npm install npm -g #更新到最新版本 npm i uniq | npm ins…...
【bug 记录】yolov5_C_demo 部署在 rv1126
问题1:opencv find 不到 在 CMakeLists 中将正确的 OpenCV库 路径添加到 CMAKE_PREFIX_PATH 变量中 set(CMAKE_PREFIX_PATH “/mnt/usr/local” ${CMAKE_PREFIX_PATH}) 问题2: rknn_api.h 找不到 将该文件从别处复制到项目 include 文件夹 问题3&…...
[vue-admin-template实战笔记]
1.克隆项目 git clone gitgitee.com:panjiachen/vue-admin-template.git 2.安装依赖 npm install 3.运行项目就会自动打开网页,并且热部署插件 npm run dev 4.查看代码 //将vue-admin-template拖入到idea中即可查看代码 1)并且发现,常用的东西已经集…...

unity 限制 相机移动 区域(无需碰撞检测)
限制功能原著地址:unity限制相机可移动区域(box collider)_unity限制相机移动区域_manson-liao的博客-CSDN博客 一、创建限制区域 创建一个Cube,Scale大小1,添加组件:BoxCollder,调整BoxColld…...

Hudi第二章:集成Spark
系列文章目录 Hudi第一章:编译安装 Hudi第二章:集成Spark 文章目录 系列文章目录前言一、安装Spark1、安装Spark2.安装hive 二、spark-shell1.启动命令2.插入数据3.查询数据1.转换DF2.查询 3.更新4.时间旅行5.增量查询6.指定时间点查询7.删除数据1.获取…...

springboot和vue:八、vue快速入门
vue快速入门 新建一个html文件 导入 vue.js 的 script 脚本文件 <script src"https://unpkg.com/vuenext"></script>在页面中声明一个将要被 vue 所控制的 DOM 区域,既MVVM中的View <div id"app">{{ message }} </div…...
docker-compose内网本地安装
1:通过包管理器安装 Docker Compose,请按照以下步骤进行操作: 首先,确保你的系统上已经安装了 Docker。如果尚未安装 Docker,请根据你的操作系统使用适当的包管理器进行安装打开终端,并运行以下命令下载 D…...
ThreeJs的场景实现鼠标拖动旋转控制
前面一个章节中已经实现在场景中放置一个正方体,并添加灯光使得正方体可见。但是由于是静态的还不能证明是3D的,我们需要添加一些控制器,使得通过鼠标控制正方体可以动起来,实现真正的3D效果,由此引入OrbitControls组件…...
jdk 管理工具比对 jEnv jabba SDKMAN
jEnv、jabba、SDKMAN 这三个 JDK 管理工具进行的比对: jEnv: 地址:https://github.com/jenv/jenv 作者:Gildas Cuisinier 最后更新时间:2021年5月26日 开发语言:Shell Jabba: 地址࿱…...

华为云云耀云服务器L实例评测|部署在线图表和流程图绘制工具drawio
华为云云耀云服务器L实例评测|部署在线图表和流程图绘制工具drawio 一、云耀云服务器L实例介绍1.1 云服务器介绍1.2 优势及其应用场景1.3 支持镜像 二、云耀云服务器L实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置 三、部署 drawio3.1 drawio 介绍3.2 Docker 环…...

elementui引入弹出框报错:this.$alert is not defined 解决方案
1.按需引入文件element.js 注意:引入Message,MessageBox两个组件就行,alert包括在MessageBox里面了。 之前我引入了Alert组件,发现不行 2.在vue的prototype里注册伪名字 3.组件里直接调用就行了 4.实现效果 我发现elementui调用…...
docker的组件和资源管理
Docker是一种开源的容器化平台,它提供了一种轻量级、可移植和可扩展的方式来打包、部署和运行应用程序。Docker的构成包括以下几个关键组件: Docker Engine:Docker Engine是Docker的核心组件,它负责管理容器的生命周期和资源隔离…...

SEO的优化教程(百度SEO的介绍和优化)
百度SEO关键字介绍: 百度SEO关键字是指用户在搜索引擎上输入的词语,是搜索引擎了解网站内容和相关性的重要因素。百度SEO关键字可以分为短尾词、中尾词和长尾词,其中长尾词更具有针对性和精准性,更易于获得高质量的流量。蘑菇号-…...
Tomcat以及UDP
一、Tomcat 服务端 自定义 S Tomcat服务器 S :Java后台开发 客户端 自定义 C 浏览器 B 认识一些常用的目录: bin:存放开始和结束的程序 conf:配置文件 lib:组成包 logs:输出日志 webapps&#x…...

NLP 04(GRU)
一、GRU GRU (Gated Recurrent Unit)也称门控循环单元结构,它也是传统RNN的变体,同LSTM一样能够有效捕捉长序列之间的语义关联, 缓解梯度消失或爆炸现象,同时它的结构和计算要比LSTM更简单,它的核心结构可以分为两个部分去解析: 更新门、重置门 GRU的内…...

BUUCTF reverse wp 51 - 55
findKey shift f12 找到一个flag{}字符串, 定位到关键函数, F5无效, 大概率是有花指令, 读一下汇编 这里连续push两个byte_428C54很奇怪, nop掉下面那个, 再往上找到函数入口, p设置函数入口, 再F5 LRESULT __stdcall sub_401640(HWND hWndParent, UINT Msg, WPARAM wPara…...
WebGL笔记:使用鼠标绘制多个线条应用及绘制动感线性星座
使用鼠标绘制多个线条 多个线条,肯定不是一笔画过的,而是多次画的线条既然是多线,那就需要有个容器来管理它们 1 )建立容器对象 建立一个 lineBox 对象,作为承载多边形的容器 // lineBox.js export default class …...

python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

Golang——7、包与接口详解
包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

渗透实战PortSwigger Labs指南:自定义标签XSS和SVG XSS利用
阻止除自定义标签之外的所有标签 先输入一些标签测试,说是全部标签都被禁了 除了自定义的 自定义<my-tag onmouseoveralert(xss)> <my-tag idx onfocusalert(document.cookie) tabindex1> onfocus 当元素获得焦点时(如通过点击或键盘导航&…...

构建Docker镜像的Dockerfile文件详解
文章目录 前言Dockerfile 案例docker build1. 基本构建2. 指定 Dockerfile 路径3. 设置构建时变量4. 不使用缓存5. 删除中间容器6. 拉取最新基础镜像7. 静默输出完整示例 docker runDockerFile 入门syntax指定构造器FROM基础镜像RUN命令注释COPY复制ENV设置环境变量EXPOSE暴露端…...

Python爬虫(52)Scrapy-Redis分布式爬虫架构实战:IP代理池深度集成与跨地域数据采集
目录 一、引言:当爬虫遭遇"地域封锁"二、背景解析:分布式爬虫的两大技术挑战1. 传统Scrapy架构的局限性2. 地域限制的三种典型表现 三、架构设计:Scrapy-Redis 代理池的协同机制1. 分布式架构拓扑图2. 核心组件协同流程 四、技术实…...

分类数据集 - 场景分类数据集下载
数据集介绍:自然场景分类数据集,真实场景高质量图片数据;适用实际项目应用:自然场景下场景分类项目,以及作为通用场景分类数据集场景数据的补充;数据集类别:buildings、forest、glacier、mounta…...