c保险编码标准中整数加法溢出的判断方法分析(补码)

c安全编码标准中整数加法溢出的判断方法分析(补码)
    c语言中判断整数加法运算溢出的方法有很多,在c安全编码标准当中就有两个,其中利用补码这个,只给了表达式,没有讲原理,我这里分析了一下,求大神批评!
    这是书里给出的判断表达式if(((si1^si2) | (((si1^(~(si1^si2) & (1 << (sizeof(int)*CHAR_BIT-1))))+si2)^si2)) >= 0)),这个表达式为真就是要溢出,其中si1和si2是两个整数,CHAR_BIT应该就是一个字节的位数,也就是8位,这里写成这样应该是考虑到移植性吧,补码的知识需要大家百度了,我就不罗嗦了,下面开始分析这个式子:
首先我们从里开始, (1 << (sizeof(int)*CHAR_BIT-1)),这部分求出int型的字节数然后计算出对应的位数,减去1之后对1进行了左移,最终得到了一个最高位为1其余位为0的int型值,这个实现是可移植的,因为没有默认int型为32或者64位等。得到这个值之后要和~(si1^si2)这个表达式进行&操作,这时候我们知道,我们关注的是最高位也就是符号位,好了,那么~(si1^si2)这个表达式我们就好分析了,异或的操作结果取决于!这两个数是否同号!,(其实我们知道两个数相加,只有同号的时候才有可能溢出,一会儿也会用到这个理论的,先说一下),所以(~(si1^si2) & (1 << (sizeof(int)*CHAR_BIT-1)))这个结果就是通过判断是否同号来决定符号位是什么,这里,同号的话结果为1,异号为0,由于接下来这个结果要和si1异或再加上si2所以说,异号的情况不用分析了,这个加法本身就不溢出,同号的时候和si1异或就改变了符号位就是取反,这样首先保证再和si2相加的时候不会溢出,同时我们需要分析一下这个计算的过程,在补码的世界里符号位取反可不是正负数变换,而是(这里我用自己的话说一下)算出其到边界的距离(该数减去距离最近的模值,是时候来个例子了,8位的有符号数,相当于7位数,模值就是128,所以这个数是负数就减-128,为正就减128),由于这个计算有正负之分,在与si2相加后,就能得判断出si2能否弥补这段距离,即是否溢出(这时候si1和si2是同号,正数的情况下,减去128计算结果为负,加上si2后结果为正的话说明si2能够弥补这段距离,那就是溢出了,如果为负即没有溢出,负数的情况同理),好啦,这个判断结果和(si1^si2)这个式子进行或运算,当然我们还是只关心符号位,(si1^si2)这个式子就是判断是否同号,异号就直接过啦,同号就得看后面的判断结果了。
    说了这么多,有点儿啰嗦,因为里面有自己的猜想,所以希望大神给看看,这样分析对吗?
------解决思路----------------------
学习了,分析的挺好
要是好好排下版,观众应该会更多的,这么一大段看着太累了
------解决思路----------------------
if (
    (
        (si1^si2)
        
------解决思路----------------------

        (
            (
                (
                    si1^(
                        ~(si1^si2)
                        &
                        (
                            1 << (sizeof(int)*CHAR_BIT-1)
                        )
                    )
                )
                +si2
            )
            ^si2
        )
    )
    >= 0
)

//有符号整形a和b,如何判断a+b是否溢出
#pragma warning(disable:4035)
#include <stdio.h>
int ifo_add(int a,int b) {
    __asm {
        mov eax,a
        add eax,b
        jo  overflowed
        xor eax,eax
        jmp no_overflowed
overflowed:
        mov eax,1
no_overflowed:
    }
}
int main() {
    int a,b;

    a=          1;b= 2;printf("%11d+(%2d) %d\n",a,b,ifo_add(a,b));
    a=         -1;b=-2;printf("%11d+(%2d) %d\n",a,b,ifo_add(a,b));
    a= 2147483647;b= 1;printf("%11d+(%2d) %d\n",a,b,ifo_add(a,b));
    a=-2147483647;b=-1;printf("%11d+(%2d) %d\n",a,b,ifo_add(a,b));
    a=-2147483647;b=-2;printf("%11d+(%2d) %d\n",a,b,ifo_add(a,b));
}
//          1+( 2) 0
//         -1+(-2) 0
// 2147483647+( 1) 1
//-2147483647+(-1) 0
//-2147483647+(-2) 1