运算符(除法)
来源:互联网 发布:js日期转换为数字 编辑:程序博客网 时间:2024/05/18 09:37
本节所有数学公式并不存在有符号无符号之说,需要加以区分
当除数为变量,被除数为常量 C / V
int _tmain(int argc, _TCHAR* argv[]){ int n; unsigned m; scanf("%d", &n); scanf("%d", &m); printf("%d", 8 / n); printf("%d", 8 / m); return 0;}
无论是 Debug版 还是 Release版 ,反汇编结构都是相似的,都是直接使用 div 或者 idiv 这种直观的除法指令。
有符号变量
有符号变量作为除数生成的反汇编代码中,一般会成对编写 cdq 和idiv。
cdq:把 edx 的所有位都设成 eax 最高位的值。也就是说,当 eax < 0x80000000, edx = 0x00000000;当 eax >= 0x80000000, edx = 0xFFFFFFFF)。
idiv:表示有符号位的除法,相对应的无符号位除法 div。
无符号变量
无符号变量作为除数生成的反汇编代码中,一般会成对编写 xor 和div。
当被除数为变量,除数为常量(正数) V / C
int _tmain(int argc, _TCHAR* argv[]){ int n; unsigned m; scanf("%d", &n); scanf("%d", &m); printf("%d", n / 8); printf("%d", m / 16); printf("%d", m / 0x87654321); return 0;}
有符号变量除以 2 的幂
Debug版 和 Release版 生成的反汇编代码结构相似,生成反汇编如下:
该公式由数学公式推导而来,形成了下列定式:
cdqand edx, immAadd eax, edxsar eax, immB
若
无符号变量除以 2 的幂
Debug版 和 Release版 生成的反汇编代码结构相似,生成反汇编结构如下:
无符号变量除以非 2 的幂(情况一)
在 Debug版 下,直接使用了指令 div
在 Release版 下,生成的汇编代码如下
该汇编结构也由数学公式推导而来,形成了下列定式:
mov eax, Mmul Ashr edx, imm
求除数的计算公式为:
”粗糙“ 的公式推导求证
设
=>
=>设
结合代码,
有符号变量除以非 2 的幂(情况一)
int _tmain(int argc, _TCHAR* argv[]){ printf("%d", argc / 5); return 0;}
生成的反汇编如下:
其代码定式为:
mov eax, Mimul Asar edx, immmov reg, edxshr reg, 1Fhadd reg, edx
求除数的计算公式同样为:
我们知道,这与 无符号变量除以非 2 的幂(情况一) 的汇编指令相似,不同的是,多了下列三条指令。这块指令仅是用于调整代码:如果最高位为 0,则无需调整(加 0 );如果最高位为 1,则需要加 1。在不同的平台上,可能会有不同的表现形式。
mov reg, edxshr reg, 31add reg, edx
无符号变量除以非 2 的幂(情况二)
int _tmain(int argc, _TCHAR* argv[]){ unsigned int n = 0; scanf("%d", &n); printf("%d", n / 7); return 0;}
生成的反汇编代码如下:
代码定式为:
mov eax, Mmul Asub A, edxshr A, imm_1add A, edxshr A, imm_2
求除数的计算公式为:
“粗糙”的公式推导求证
从上面的 代码定式 中,可以知道:
如果将 代码定式 逐步执行,转成数学公式的话,得到以下式子:
dadadadadadada….经过一系列转换,变成:
在 无符号变量除以非 2 的幂(情况一) 中我们推导过公式:
有符号变量除以非 2 的幂(情况二)
int _tmain(int argc, _TCHAR* argv[]){ int n = 0; scanf("%d", &n); printf("%d", n / 7); return 0;}
生成的反汇编代码如下:
代码定式为:
mov eax, Mimul Aadd edx, Asar edx, immmov reg, edxshr reg, 1Fhadd reg, edx
求除数的计算公式为:
“粗糙”的推导求证—关于第三条指令 add edx, A
假设在 16 位系统环境下,有符号数 A 乘以 8086h,如果将 8086h 视为无符号相乘,那么代码如下:
mov ax, 8086himul Aadd dx, A
为什么最后需要有 add dx, A 这条指令呢?由于编译器是将 8086h 作为有符号相称,其结果用数学公式表示为:
但实际上,
为什么在这里
M 实际上是一个无符号数?因为M 是由2nc 计算出来的。在这里 c 一定是一个正数,所以M 也一定是一个正数。
当被除数为变量,除数为常量(负数) V / C
如果无符号作为变量,常量为负数时,该常量也会被视为无符号,也就是 > 0x80000000。此时指令一定为 Div,在此不再讨论。下面只讨论有符号。
除以 2 的幂
int _tmain(int argc, _TCHAR* argv[]){ int n; scanf("%d", &n); printf("%d", n / -4); return 0;}
生成的反汇编代码如下,没什么好说的了…:
除以非 2 的幂(情况一)
int _tmain(int argc, _TCHAR* argv[]){ int n; scanf("%d", &n); printf("%d", n / -3); return 0;}
生成的反汇编代码如下:
代码定式:
mov eax, Mimul Asub edx, Asar edx, immmov reg, edxmov reg, 1Fhadd reg, edx
“粗糙”的解释
sub edx, A 这条指令为调整指令。当 M 为负数时,才需要有这条指令。如果该有调整指令而没有该指令,或者不该有调整指令而又调整指令,都需要对 M 求补来得到“真正的
除以非 2 的幂(情况二)
int _tmain(int argc, _TCHAR* argv[]){ int n; scanf("%d", &n); printf("%d", n / -9); return 0;}
生成的反汇编代码如下:
代码定式:
mov eax, Mimul Asar edx, immmov reg, edxmov reg, 1Fhadd reg, edx
在 除以非 2 的幂(情况一) 中讨论过,由于是有符号乘法,M为负数,而没有调整代码,所以需要对
求除数的公式:
- 运算符(除法)
- python 学习笔记之 算术运算符(除法)
- 除法运算
- 除法运算
- 除法运算符/与/的区别
- C++运算符重载实现矩阵除法
- 《除法与取余运算符》
- 运算符除法 “/” 和 "//"的区别
- 乘法/除法 转移位运算符
- 用字符串模拟除法运算
- hdu 2117 (模拟除法运算)
- C语言除法运算符“/”和求余运算符“%”
- C语言除法运算符“/”和求余运算符“%”
- C语言除法运算符“/”和求余运算符“%”
- C语言除法运算符“/”和求余运算符“%”
- C语言除法运算符“/”和求余运算符“%”
- 除法运算符和求余运算符
- C语言除法运算符“/”和求余运算符“%”
- Seaborn学习以及Matplotlib基础(持续更新中...)
- 自勉
- javaWeb之struts四---文件上传篇
- 二叉树
- error during connect: Get http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.32/info: open //./pipe/docker_eng
- 运算符(除法)
- CentOS设置IP
- [译文]Android架构组件-App架构指南
- using语句下使用SqlDataReader异常:Invalid attempt to Read when reader is closed
- 内置锁(三)---- synchronized的几个要注意的对象监视器
- mysql常规命令
- VTK 7.1.0+window7_64位+QT5.5配置及第一个实例运行
- java开发遇到的简单问题
- 二叉树的顺序存储实现及遍历