前言:

经过前面几篇的学习,我们了解到指令的大概分类,如:

参数加载指令,该加载指令以 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)指令,用于在动态生成的代码中执行各种数学运算、位操作和比较操作。

这些指令允许开发人员对操作数进行加法、减法、乘法、除法、逻辑与、逻辑或、逻辑非、位与、位或、位异或、左移、右移以及比较等操作。

通过运算操作指令,开发人员能够在动态生成的代码中实现各种算术运算、逻辑运算和位操作,从而更灵活地处理数据和实现复杂的逻辑。

这些指令为动态代码生成提供了强大的功能,使得开发人员能够根据需要生成高效且功能丰富的代码。

运算操作指令的分类:

让我们按照分类逐一介绍各种指令以及它们的详细用途。

  1. 算术运算指令:

    • add(加法):将两个值相加,并将结果推送到计算栈上。主要用于执行整数和浮点数的加法操作。
    • sub(减法):将一个值减去另一个值,并将结果推送到计算栈上。用于执行整数和浮点数的减法操作。
    • mul(乘法):将两个值相乘,并将结果推送到计算栈上。用于执行整数和浮点数的乘法操作。
    • div(除法):将一个值除以另一个值,并将结果推送到计算栈上。用于执行整数和浮点数的除法操作。
  2. 逻辑运算指令:

    • and(与):对两个整数进行按位与操作,并将结果推送到计算栈上。用于执行逻辑与操作。
    • or(或):对两个整数进行按位或操作,并将结果推送到计算栈上。用于执行逻辑或操作。
    • xor(异或):对两个整数进行按位异或操作,并将结果推送到计算栈上。用于执行逻辑异或操作。
  3. 位操作指令:

    • shl(左移):将一个整数向左移动指定的位数,并将结果推送到计算栈上。用于执行左移操作。
    • shr(右移):将一个整数向右移动指定的位数,并将结果推送到计算栈上。用于执行算术右移操作。
    • not(非):对一个整数进行按位取反操作,并将结果推送到计算栈上。用于执行按位取反操作。
  4. 比较操作指令:

    • 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 指令方法:运算操作指令(指令篇结束)的更多相关文章

  1. Golang入门教程(十三)延迟函数defer详解

    前言 大家都知道go语言的defer功能很强大,对于资源管理非常方便,但是如果没用好,也会有陷阱哦.Go 语言中延迟函数 defer 充当着 try...catch 的重任,使用起来也非常简便,然而在 ...

  2. Docker入门教程(六)另外的15个Docker命令

    Docker入门教程(六)另外的15个Docker命令 [编者的话]DockerOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第六篇,继续介绍Docker命令.之前的第二篇文章 ...

  3. 无废话ExtJs 入门教程十六[页面布局:Layout]

    无废话ExtJs 入门教程十六[页面布局:Layout] extjs技术交流,欢迎加群(201926085) 首先解释什么是布局: 来自百度词典的官方解释:◎ 布局 bùjú: [distributi ...

  4. Photoshop入门教程(六):通道

    学习心得:当大部分人听到通道.心里可能会有一种很害怕的感觉,因为“通道”并不像“图层”这样易于理解,望而生畏.”通道“的本质其实是存储图片的信息,把一张图片比作一个为网站,那么通道就是网站的后台,存储 ...

  5. RabbitMQ入门教程(十六):RabbitMQ与Spring集成

    原文:RabbitMQ入门教程(十六):RabbitMQ与Spring集成 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https: ...

  6. ASP.NET MVC 5 学习教程:Edit方法和Edit视图详解

    原文 ASP.NET MVC 5 学习教程:Edit方法和Edit视图详解 起飞网 ASP.NET MVC 5 学习教程目录: 添加控制器 添加视图 修改视图和布局页 控制器传递数据给视图 添加模型 ...

  7. SpringMVC强大的数据绑定(2)——第六章 注解式控制器详解

    SpringMVC强大的数据绑定(2)——第六章 注解式控制器详解 博客分类: 跟开涛学SpringMVC   6.6.2.@RequestParam绑定单个请求参数值 @RequestParam用于 ...

  8. 转:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法、shiro认证与shiro授权

    原文地址:JAVAWEB开发之权限管理(二)——shiro入门详解以及使用方法.shiro认证与shiro授权 以下是部分内容,具体见原文. shiro介绍 什么是shiro shiro是Apache ...

  9. 【入门】广电行业DNS、DHCP解决方案详解(三)——DNS部署架构及案

    [入门]广电行业DNS.DHCP解决方案详解(三)——DNS部署架构及案 DNS系统部署架构 宽带业务DNS架构 互动业务DNS架构 案例介绍 案例一 案例二 本篇我们将先介绍DNS系统部署架构体系, ...

  10. mui初级入门教程(六)— 模板页面实现原理及多端适配指南

    文章来源:小青年原创发布时间:2016-07-26关键词:mui,webview,template,os,多端适配转载需标注本文原始地址: http://zhaomenghuan.github.io. ...

随机推荐

  1. vscode 文件上传快捷键 shift+alt+s (ftp专用)插件用的 ftp-sync

    vscode 文件上传快捷键 shift+alt+s (ftp专用)插件用的 ftp-sync { "key": "shift+alt+s", "co ...

  2. 开发环境篇之HALCON数据结构

    开发环境篇之HALCON基础 目录 基本数据分类 图标类数据 Image(图片) Pixel:像素 Channel:通道 Domain:域 图片操作 Region(区域) Region操作 XLD(轮 ...

  3. Ingress和Ingress Controller什么关系

    Ingress Controller和Ingress在Kubernetes(K8s)中各自扮演着不同的角色,但它们共同协作以实现外部访问集群内部服务的功能. Ingress是一个Kubernetes ...

  4. Python使用os模块创建带时间戳的文件夹

    直接上源码: # 导入os模块 import os import time # 创建文件夹函数 def mkdir(path): # os.path.exists 函数判断文件夹是否存在 folder ...

  5. springboot增加slf4j

    参考:https://blog.csdn.net/qq_27706119/article/details/104977666(主要) https://www.liaoxuefeng.com/wiki/ ...

  6. WINDOWS.H already included. MFC apps must not #include Windows.h

    做C++.C#和C++/CLI的混合编程有一段时间了,填了不少的坑. 今天又遇到一错误,想着挺容易就解决,估计是大脑疲惫,折腾许久才找到原因. 错误: 错误 C1189 #error: WINDOWS ...

  7. 编译器与Makefile

    编译器与Makefile 目录 编译器与Makefile gcc/g++/clang clang gcc g++ 编译器过程 Makefile 什么是Makefile Makefile规则 变量 in ...

  8. Linux 串口驱动实例简单分析(x86 8250驱动(16550A),TIOCMGET, TIOCMSET, RTS)

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  9. CentOS 同时安装多个版本的Python3

    1.背景 已安装了 Python3.6.4,需要再安装 Python3.9 版本 2.操作步骤 (1)寻找当前 Python3.9 版本最新稳定版的子版本 通过官网查找,目前为 3.9.18,下载到本 ...

  10. Django:Nginx 启动,无法加载样式,无法加载静态文件

    一般是由于 Nginx 配置文件的问题 # 编辑 Nginx 配置文件 vim /etc/nginx/nginx.conf # 如果出现下面这个 use nginx 就需要改成 use root 保存 ...