整数算术溢出问题的分析

    这篇对整数的一些基本运算产生的溢出问题进行分析。

  当你进行加减乘除运算的时候,如果这个数字很大,运算产生的结果就可能会出乎你最初设计程序的预料,这对程序来说是一种很可怕的漏洞,这让一些恶意的访问者对程序作出一些破坏性的事情,这样造成的危害可能是很大的。

这里先定义一些宏定义作为返还值:

#define OVERFLOW 1      //算术溢出(正溢出)
#define NOT_OVERFLOW 0             //未溢出
#define NEGATIVE_OVERFLOW -1      //负溢出

当进行无符号整数加法计算的时候。

  无符号整数的范围是 0 ≤ x  UMax ,UMax = 2w - 1 (w是当前类型的位数) ,如果两个数相加的结果小于任何一个数,那么就可以判断算术溢出。判断的代码如下:

int uadd_ok(unsigned x, unsigned y)
{
    unsigned uadd=x+y;
    if( uadd < x || uadd < y)
        return OVERFLOW;
        
    return NOT_OVERFLOW;
}

当进行有符号整数加法计算的时候。

  有符号整数的范围是 TMin ≤ x ≤ TMax TMin = -2w-1 ,TMax = 2w-1 - 1 那么为什TMax的绝对之为什么会比TMin的绝对之小一,那么假设 w= 4 观察一下。因为有符号数的最高位是符号位,所以TMax的最高位就是 0 ,为了让数字更大那么其余就应该是 1 ,那么 TMax (4) = 0111 = 22+21+20=23-1=2w-1-1。有符号数的负数部分一般都是用补码表示的 TMin 最高位就需要是 1 因为只有最高位是代表负数,其余位都是正数,最后这个数的值是各个位的值的加和得到的,所以其余位都需要是 0 ,那么 TMin(4)=1000= -23 = -2w-1 。那么判断有符号数加法的代码一种错误如下,它利用了阿贝尔群得知补码加法的时候,(x+y)-y=y 在溢出的情况下是成立的。所以就有可能出现如下的代码:

int tadd_ok(int x, int y)
{
     int sum=x+y;
     return (sum - y == y) && (sum - x == y) ; 
}    

但是这个代码的返回值永远是 1, 因为在不溢出的情况下表达式成立是显而易见的。

所以就需要考虑多方面的因素了,两个数都大于零的时候,如果结果是负数那么可判断溢出。如果两个数都是负数,结果为正数那么判断也溢出。

代码如下:

int tadd_ok(int x, int y)
{
    int tadd=x+y;
    if( x > 0 && y > 0 )
        if( tadd < 0 )
            return OVERFLOW;
    
    if( x < 0 && y < 0 )
        if( tadd >= 0 )
            return NEGATIVE_OVERFLOW;
    
    return NOT_OVERFLOW;
}

当进行有符号减法运算的时候。

  这个时候你可能想像这样调用写好的 tadd_ok( x, -y );  函数,但是实际上在一些情况下这是错误的,因为 TMin = -TMin ,这样你想要的 -TMin 就没有变成 | TMin | 却变成了TMin 所以就需要增加一些判断。

代码如下:

int tsub_ok(int x, int y)
{
    if( y != 0 && y == -y )
    {
        if( x >= 0 )
            return OVERFLOW;
        return NOT_OVERFLOW;
    }
    return tadd_ok(x,-y);
}

当是乘法运算的时候不论有符号还是无符号,溢出的部分都是直接截掉的。

  当然乘法是可以使用 ( x * y ) / x = y 进行判断的因为溢出的时候这是不成立的,当然你需要保证 x , y 不是零 ,如果是零作为除数是不合理的。

所以可以写出如下代码:

int tmult_ok(int x, int y)
{
    int tmult=x*y;
    if( x != 0 && y!= 0 )
    {
        if( tmult / x == y )
            return NOT_OVERFLOW;
        return OVERFLOW;
    }
    return NOT_OVERFLOW;
}

  

原文地址:https://www.cnblogs.com/foreverW/p/7512859.html