方法一:
境遇:假设要判断两个整数的加法运算是否溢出。
C#中的checked/unchecked关键字能和方便的检查运算是否溢出,但是我们在C++中怎么做呢?溢出也不像C#会抛出异常,别忘了C/C++的特点:我们可以直接操纵底层硬件!把寄存器溢出标志位取出来就可以了。虽然只对加法做了溢出判断,但有了下面这段示例也能判断其它运算的溢出了。
//Copyright By Renjiachao
//By Renjiachao 2010-10-13
#include<iostream>
#include<string>
using namespace std;
class SafeInt //signed int
{
friend const SafeInt operator+(const SafeInt& lhs, const SafeInt& rhs);
friend ostream& operator<<(ostream& out, const SafeInt& si)
{ out<<si.val; return out; }
public:
SafeInt(int v=0):val(v) {}
operator int() {return val;}
SafeInt& operator+=(const SafeInt& rhs)
{
val += rhs.val;
unsigned long dwEAX = 0;
__asm //汇编代码鸣谢:贾宁宇
{
PUSH EAX //压入EAX寄存器的值作为保护
PUSHFD //将EFLAGS寄存器的全部内容压入堆栈
POP EAX //把刚刚入栈的EFLAGS寄存器的值取出放入EAX
MOV dwEAX,EAX //把EAX中的值放入dwEAX变量中
POP EAX //恢复EAX寄存器的值
}
if (dwEAX & 0x00000800) //取出第11(基于0)位的值
throw overflow_error("溢出");
return *this;
}
private:
int val;
};
const SafeInt operator+(const SafeInt& lhs, const SafeInt& rhs)
{
SafeInt temp(lhs);
temp+=rhs;
return temp;
}
int main()
{
SafeInt i1 = 10;
SafeInt i2 = INT_MAX - 11;
SafeInt iSum = 0;
try
{
iSum = i1 + i2; //不溢出
cout<<i1<<" + "<<i2<<" = "<<iSum<<endl;
iSum = iSum + i1; //溢出
cout<<i1<<" + "<<i2<<" = "<<iSum<<endl;
}
catch(overflow_error & e)
{
cout<<e.what()<<endl;
}
return 0;
}
代码中的说明:
OF--溢出标志
EFLAGS 寄存器 的标志位大致如下表所示:
方法二:
if ((unsigned)a+(unsigned)b > INT_MAX)
complain();
此处的INT_MAXSHI是一个已定义的常量,代表可能的最大整数值。ANSI C标准在<limits.h>中定义了INT_MAX;如果是在其他C语言实现上,你也需要自己重新定义。
if (a > INT_MAX -B)
complain();
方法三:
static PyObject *
int_add(PyIntObject *v, PyIntObject *w)
{
register long a, b, x;
CONVERT_TO_LONG(v, a);
CONVERT_TO_LONG(w, b);
/* casts in the line below avoid undefined behaviour on overflow */
x = (long)((unsigned long)a + b);
if ((x^a) >= 0 || (x^b) >= 0)
return PyInt_FromLong(x);
return PyLong_Type.tp_as_number->nb_add((PyObject *)v, (PyObject *)w);
}