abs是我们常用的取绝对值的函数,并且实现也很简单,按照以往自己实现abs功能的时候,一定会选择判断输入是否大于0,然后分别处理,但是今天对abs的分析,在不使用判断语句的情况下,对一个数取了绝对值,让我对计算机处理数的方法有了更深的了解。
以及理解为何abs会在一定条件下返回一个负数。
函数介绍
功 能: 求整数的绝对值
头文件:stdlib.h
函数原型:int abs(int i);
/来自百度百科/
反汇编分析
4B2F4810 mov edi, edi ;微软给我们下HOOK的地方
4B2F4812 push ebp ; 保存ebp
4B2F4813 mov ebp, esp ;建立新的堆栈
4B2F4815 mov eax, [ebp+arg_0];将要进行绝对值转换的数移动到eax
4B2F4818 cdq ;将edx的每一位至为eax的最高位,也就是要转换的数的符号位
4B2F4819 xor eax, edx ;将要处理的数和符号位异或,如果是正数,则不会发生改变,负数则取反,并将符号位至为0
4B2F481B sub eax, edx ;由于数在计算机中以补码的形式存在,补码转原码应该取反加1,所以此处负数需要+1,正数的话edx为0不会影响
4B2F481D pop ebp ;恢复ebp
4B2F481E retn
学到的知识
短短的几行代码,并没有用到判断语句就直接计算出了数的绝对值,方法值得学习。但是关于代码中对堆栈的处理,个人觉得是否有一些的多余,因为所有的操作都是在寄存器中进行的,所以是否可以直接去掉三行代码,让代码变得更加精简呢?以及可能算bug的一个存在,就是会返回一个负数。
为何abs会返回负数
abs的作用为返回一个数的绝对值,绝对值肯定是非负数,但是我们都知道,例如一个char,他的取值范围是-128~127,那么当我们输入一个abs(-128)的时候程序会返回什么呢?答案是-128。为什么会出现这种情况呢?
在对应上来讲,由于正数的个数比负数多一个,所以不是每一个负数都能找到自己的对应正数。所以128无法返回,但是为何-128输入之后输出仍然为128呢?是因为没处理吗?当然不是。
依据上文的代码,我们可以做如下推理
eax=-128=1000 0000=0x80
edx=1111 1111=0xFF
xor eax,edx -> eax=0111 1111=0x7F
sub eax,edx -> eax=1000 0000=-128
所以此处不是因为没有处理,而是照样处理了,只是最大的负数经过这样的流程处理之后,仍然还是原数。