正如其他人所说,如果结果与两个操作数的符号不同,则会发生二次补码签名溢出.
反过来也是如此.除非操作数是相同的符号(负数或非负数)且结果相反,否则不能发生二进制补码有符号溢出.
不过,就个人而言,我更喜欢更直接的方法:
int_type a = 12356, b = 98765432;
if ( b > 0 && a > std::numeric_limits< int_type >::max() - b )
throw std::range_error( "adding a and b would cause overflow" );
if ( b < 0 && a < std::numeric_limits< int_type >::min() - b )
throw std::range_error( "adding a and b would cause underflow" );
int_type c = a + b;
Run Code Online (Sandbox Code Playgroud)
这将捕获有符号和无符号溢出/下溢,并且更容易看到发生了什么.
此外,C++中的积分有符号溢出不能保证包含,因为不需要二进制补码算法.有符号整数溢出甚至可能崩溃,尽管不太可能.因此,就语言而言,最好在溢出发生之前停止溢出.C++03§5/ 5:
如果在评估表达式期间,结果未在数学上定义或未在其类型的可表示值范围内,则行为未定义,除非此类表达式是常量表达式(5.19),在这种情况下程序生病-formed.[注意:大多数现有的C++实现忽略整数溢出....]
另请参阅Boost数字转换库,虽然我不确定它可以为这个问题做任何事情std::numeric_limits.
Chr*_*Vig -1
为了发生溢出,两个操作数必须具有相同的符号。如果操作数之和与操作数的符号不同,则发生溢出。
bool overflow( int a, int b )
{
bool op_same_sign = ( a < 0 ) == ( b < 0 );
bool sum_diff_sign = ( a < 0 ) != ( a + b < 0 );
return op_same_sign && sum_diff_sign;
}
Run Code Online (Sandbox Code Playgroud)
更简洁一点...
bool overflow( int a, int b )
{
return ( ( a < 0 ) == ( b < 0 ) && ( a + b < 0 ) != ( a < 0 ) );
}
Run Code Online (Sandbox Code Playgroud)