.NET Emit 入门教程:第六部分:IL 指令:9:详解 ILGenerator 指令方法:运算操作指令(指令篇结束)
前言:
经过前面几篇的学习,我们了解到指令的大概分类,如:
参数加载指令,该加载指令以 Ld 开头,将参数加载到栈中,以便于后续执行操作命令。
参数存储指令,其指令以 St 开头,将栈中的数据,存储到指定的变量中,以方便后续使用。
创建实例指令,其指令以 New 开头,用于在运行时动态生成并初始化对象。
方法调用指令,该指令以 Call 开头,用于在运行时调用其它方法。
支条件指令,该指令通常以 Br、或 B、C 开头,用于在运行分支条件时跳转指令。
类型转换指令,该指令通常以 Cast、Conv 开头或box结尾,用于在运行时对类型进行转换。
本篇介绍运算操作指令,介绍完后,将结束指令篇。
第六部分:IL指令完整大纲目录如下:
.NET Emit 入门教程:第六部分:IL 指令:1:概要介绍
.NET Emit 入门教程:第六部分:IL 指令:2:详解 ILGenerator 辅助方法
.NET Emit 入门教程:第六部分:IL 指令:3:详解 ILGenerator 指令方法:参数加载指令
.NET Emit 入门教程:第六部分:IL 指令:4:详解 ILGenerator 指令方法:参数存储指令
.NET Emit 入门教程:第六部分:IL 指令:5:详解 ILGenerator 指令方法:创建实例指令
.NET Emit 入门教程:第六部分:IL 指令:6:详解 ILGenerator 指令方法:方法调用指令
.NET Emit 入门教程:第六部分:IL 指令:7:详解 ILGenerator 指令方法:分支条件指令
.NET Emit 入门教程:第六部分:IL 指令:8:详解 ILGenerator 指令方法:类型转换指令
.NET Emit 入门教程:第六部分:IL 指令:9:详解 ILGenerator 指令方法:运算操作指令(指令篇结束)
运算操作指令介绍:
在.NET Emit 编程中,运算操作指令是一类关键的IL(Intermediate Language)指令,用于在动态生成的代码中执行各种数学运算、位操作和比较操作。
这些指令允许开发人员对操作数进行加法、减法、乘法、除法、逻辑与、逻辑或、逻辑非、位与、位或、位异或、左移、右移以及比较等操作。
通过运算操作指令,开发人员能够在动态生成的代码中实现各种算术运算、逻辑运算和位操作,从而更灵活地处理数据和实现复杂的逻辑。
这些指令为动态代码生成提供了强大的功能,使得开发人员能够根据需要生成高效且功能丰富的代码。
运算操作指令的分类:
让我们按照分类逐一介绍各种指令以及它们的详细用途。
算术运算指令:
add
(加法):将两个值相加,并将结果推送到计算栈上。主要用于执行整数和浮点数的加法操作。sub
(减法):将一个值减去另一个值,并将结果推送到计算栈上。用于执行整数和浮点数的减法操作。mul
(乘法):将两个值相乘,并将结果推送到计算栈上。用于执行整数和浮点数的乘法操作。div
(除法):将一个值除以另一个值,并将结果推送到计算栈上。用于执行整数和浮点数的除法操作。
逻辑运算指令:
and
(与):对两个整数进行按位与操作,并将结果推送到计算栈上。用于执行逻辑与操作。or
(或):对两个整数进行按位或操作,并将结果推送到计算栈上。用于执行逻辑或操作。xor
(异或):对两个整数进行按位异或操作,并将结果推送到计算栈上。用于执行逻辑异或操作。
位操作指令:
shl
(左移):将一个整数向左移动指定的位数,并将结果推送到计算栈上。用于执行左移操作。shr
(右移):将一个整数向右移动指定的位数,并将结果推送到计算栈上。用于执行算术右移操作。not
(非):对一个整数进行按位取反操作,并将结果推送到计算栈上。用于执行按位取反操作。
比较操作指令:
ceq
(相等比较):比较两个值是否相等,并将结果推送到计算栈上。用于执行相等比较操作。clt
(小于比较):比较一个值是否小于另一个值,并将结果推送到计算栈上。用于执行小于比较操作。cgt
(大于比较):比较一个值是否大于另一个值,并将结果推送到计算栈上。用于执行大于比较操作。
这些指令提供了丰富的功能,可以用于执行各种数学运算、逻辑运算、位操作和比较操作,从而实现各种复杂的编程逻辑。在动态生成的代码中,开发人员可以根据具体需求使用这些指令来实现所需的功能。
接下来,我们对一个指令分类,分别给出一个示例,来介绍它们的基本用法。
对于运行指令,有两个指令后缀:
_ovf: 进行溢出检查。 _un:无符号。
例如:
多数指令都带有这两个后缀,理解这两个后缀的意思,可以快速理解所有该后缀指令。
1、算术运算指令:
Add 指令:
示例代码:
MethodBuilder methodBuilder = tb.DefineMethod("MathTo", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new Type[] { typeof(int),typeof(int) }); ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Add_Ovf_Un); il.Emit(OpCodes.Ret); // 返回该值
对应代码:
其它指令使用方式一样,省去重复举例。
Add 指令对应C#代码:+
Sub 指令对应C#代码:-
Mul 指令对应C#代码:*
Div 指令对应C#代码:/
2、逻辑运算指令:
示例代码:
ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.And); il.Emit(OpCodes.Ret); // 返回该值
对应代码:
使用方式和算术指令运行其实一致:
And 指令对应C#代码:&
Or 指令对应C#代码:|
Xor 指令对应C#代码:^
3、位操作指令:
Shl 指令:左移指令,Shift Left 的简写
示例代码:
ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldc_I4,2);
il.Emit(OpCodes.Shl); il.Emit(OpCodes.Ret); // 返回该值
对应代码:
使用方式,需要在第二个参数,指定要位移的位数。
右移操作的方式和左移一样。
Not 指令:按位取反
示例代码:
MethodBuilder methodBuilder = tb.DefineMethod("MathTo", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new Type[] { typeof(int) }); ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Not); il.Emit(OpCodes.Ret); // 返回该值
对应代码:
右移操作的方式和左移一样,而 Not 指令则不需要第二个参数:
Shl 指令对应C#代码:<<
Shr 指令对应C#代码:>>
Not 指令对应C#代码:~
4、比较操作指令:
Ceq 指令:比较两个值
示例代码:
var dynamicMethod = new DynamicMethod("ConvertTo", typeof(bool), new Type[] { typeof(int), typeof(float) }, typeof(AssMethodIL_Condition)); ILGenerator il = dynamicMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ceq); il.Emit(OpCodes.Ret); // 返回该值 var result = dynamicMethod.Invoke(null, new object[] { 11, 11 });
Console.WriteLine(result);
Console.Read();
对应代码:
运行结果:
其它两个指令使用方式和 Ceq 一致:
Ceq 指令对应C#代码:==
Clt 指令对应C#代码:<
Cgt 指令对应C#代码:>
如何实现 >= 或 <=
由于没有对应的指令,所以需要用点小技巧组合,来实现该代码:
用Clt + Ceq 指令实现:>=
ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Clt); il.Emit(OpCodes.Ldc_I4, 0);
il.Emit(OpCodes.Ceq); il.Emit(OpCodes.Ret); // 返回该值
对应代码:
用Cgt + Ceq 指令实现:<=
ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Cgt); il.Emit(OpCodes.Ldc_I4, 0);
il.Emit(OpCodes.Ceq); il.Emit(OpCodes.Ret); // 返回该值
对应代码:
性能小细节提醒:
平时我们写代码,涉及 >= 或 <= 的整数字判断时候: 比如:a>=2(需要两条指令),可以写成 a>3(只要一条指令)。
总结:
在.NET Emit编程中,我们探讨了运算操作指令的重要性和应用。
这些指令包括各种数学运算、位操作和比较操作,能够在动态生成的代码中实现对数据的处理和操作。
通过这些指令,开发人员可以灵活地进行算术运算、逻辑运算和比较操作,从而实现各种复杂的算法和逻辑。
在实际应用中,我们可以利用这些指令来实现诸如加密算法、数值计算、逻辑判断、数据压缩等功能。
通过深入理解和熟练运用这些运算操作指令,开发人员可以提高动态代码生成的效率和灵活性,从而更好地满足各种编程需求。
同时,对ILGenerator指令方法的进一步学习也能够帮助开发人员更加灵活地控制动态生成的代码,实现更复杂的功能和逻辑。
本篇之后,将进入第七部分:实战项目
.NET Emit 入门教程:第六部分:IL 指令:9:详解 ILGenerator 指令方法:运算操作指令(指令篇结束)的更多相关文章
- Golang入门教程(十三)延迟函数defer详解
前言 大家都知道go语言的defer功能很强大,对于资源管理非常方便,但是如果没用好,也会有陷阱哦.Go 语言中延迟函数 defer 充当着 try...catch 的重任,使用起来也非常简便,然而在 ...
- Docker入门教程(六)另外的15个Docker命令
Docker入门教程(六)另外的15个Docker命令 [编者的话]DockerOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第六篇,继续介绍Docker命令.之前的第二篇文章 ...
- 无废话ExtJs 入门教程十六[页面布局:Layout]
无废话ExtJs 入门教程十六[页面布局:Layout] extjs技术交流,欢迎加群(201926085) 首先解释什么是布局: 来自百度词典的官方解释:◎ 布局 bùjú: [distributi ...
- Photoshop入门教程(六):通道
学习心得:当大部分人听到通道.心里可能会有一种很害怕的感觉,因为“通道”并不像“图层”这样易于理解,望而生畏.”通道“的本质其实是存储图片的信息,把一张图片比作一个为网站,那么通道就是网站的后台,存储 ...
- RabbitMQ入门教程(十六):RabbitMQ与Spring集成
原文:RabbitMQ入门教程(十六):RabbitMQ与Spring集成 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https: ...
- ASP.NET MVC 5 学习教程:Edit方法和Edit视图详解
原文 ASP.NET MVC 5 学习教程:Edit方法和Edit视图详解 起飞网 ASP.NET MVC 5 学习教程目录: 添加控制器 添加视图 修改视图和布局页 控制器传递数据给视图 添加模型 ...
- SpringMVC强大的数据绑定(2)——第六章 注解式控制器详解
SpringMVC强大的数据绑定(2)——第六章 注解式控制器详解 博客分类: 跟开涛学SpringMVC 6.6.2.@RequestParam绑定单个请求参数值 @RequestParam用于 ...
- 转:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法、shiro认证与shiro授权
原文地址:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法.shiro认证与shiro授权 以下是部分内容,具体见原文. shiro介绍 什么是shiro shiro是Apache ...
- 【入门】广电行业DNS、DHCP解决方案详解(三)——DNS部署架构及案
[入门]广电行业DNS.DHCP解决方案详解(三)——DNS部署架构及案 DNS系统部署架构 宽带业务DNS架构 互动业务DNS架构 案例介绍 案例一 案例二 本篇我们将先介绍DNS系统部署架构体系, ...
- mui初级入门教程(六)— 模板页面实现原理及多端适配指南
文章来源:小青年原创发布时间:2016-07-26关键词:mui,webview,template,os,多端适配转载需标注本文原始地址: http://zhaomenghuan.github.io. ...
随机推荐
- Java/Kotlin Double保留小数点后几位
下面以保留2位小数,且按照四舍五入规则的例子 方法 1.BigDecimal.setScale() 此方法得到的还是个double数值 double one = 5.864; BigDecimal t ...
- Window资源管理器插件增强,可显示Android的apk图标
身为Android开发人员,更习惯看到apk的图标,但是windows系统默认不支持显示pak图标,找了会插件,终于是找到了 安装 下载软件压缩包,下载地址:https://stars-one.lan ...
- stream使用汇总
整理了下java使用stream处理list的几个便捷的方法 准备数据 List<KnowledgeInfoTable> knowledgeInfoTables = knowledgeIn ...
- JSF之Action 与ActionListener的区别
事件 检验 参数 事件产生 页面跳转 Action 有 无参数,不传入当前控件,有返回值 当铵钮被单击时产生事件.提交表单 返回页面---根据配置文件跳转 ActionLis ...
- 毕设系列之Libx264实时视频流(YUV 420P转H264视频编码篇)
PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明 本文作为本人csdn blog的主站的备份.(Bl ...
- 【atcoder beginner 308E - MEX】
前缀和 二分查找 打表枚举 代码如下 import java.io.BufferedReader; import java.io.IOException; import java.io.InputSt ...
- 不要升级!不要升级!MacOS 14.4 引发Java 应用崩溃
如果最近您收到了MacOS 14.4的升级提醒,那么建议你暂时先不要升级! 在x上,Java开发领域的一些大v们,也发现了这个问题,并提醒大家不要升级. 根据Java官方发布的文章了解到,该问题主要是 ...
- C++中虚表是什么
虚函数表,以及虚函数指针是实现多态性(Polymorphism)的关键机制.多态性允许我们通过基类的指针或引用来调用派生类的函数 定义 虚函数(Virtual Function) 定义:类中使用vir ...
- 记录--Uniapp + TypeScript 配置文档
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 0 目标 使用 uniapp + TypeScript 为基础栈进行小程序开发 uniapp 是一个使用 Vue.js 开发所有前端应用 ...
- 在 Google Colab 中使用 JuiceFS
Google Colaboratory(Colab)是一个由 Google 提供的云端 Jupyter 编程笔记本,直接通过浏览器即可进行 Python 编程.Colab 充分利用谷歌的闲置云计算资源 ...