C#中的数值溢出检查

C#中的数值溢出检查

在 C# 中进行算术运算、数值类型转换时,可能发生边界溢出问题。比如对于 32 位整型(int),最大值为$2^{31}-1$,最小值为$-2^{31}$,如果超出此范围即为越界。

一般处理越界有两种方法,第一种是采用 System.OverflowException 异常捕获机制,第二种是执行算术运算之前进行越界检查。

System.OverflowException异常捕获

在 C# 中有两种情况会引发 System.OverflowException 异常:

  • 执行算术运算时,运算结果超过类型范围
  • 数值类型转换时,比如 int 向 byte 转换

数值运算引发越界:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static void Main(string[] args)
{
int value = 780000000;
checked
{
try
{
// Square the original value.
int square = value * value;
Console.WriteLine("{0} ^ 2 = {1}", value, square);
}
catch (OverflowException)
{
double square = Math.Pow(value, 2);
Console.WriteLine("Exception: {0} > {1:E}.",square, Int32.MaxValue);
}
}
}

大范围类型向小范围类型转换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static void Main(string[] args)
{
byte value = 241;
checked
{
try
{
sbyte newValue = (sbyte)value;
Console.WriteLine("Converted the {0} value {1} to the {2} value {3}.",
value.GetType().Name, value,
newValue.GetType().Name, newValue);
}
catch (OverflowException)
{
Console.WriteLine("Exception: {0} > {1}.", value, SByte.MaxValue);
}
}
}

这里需要特别注意的是,需要进行越界检查的代码,必须在 checked 块中,否则系统将不会引发越界异常。

提前检查

对于可能发生越界的运算,在进行计算之前,对运算进行越界评估,比如下面:

1
2
3
4
5
6
7
8
9
10
11
12
class Program
{
static void Main(string[] args)
{
int i = 2147483640;
if( i > int.MaxValue - 10)
{
Console.WriteLine("Overflow");
}
i += 10;
}
}

对于其他运算也是类似,只不过检查方法有些差别。这种方法也存在一些局限性,通常只用在整型的检查,对于浮点类型来说,由于精度影响,计算出来的结果可能会有误差。所以在实际项目中,最好采用第一种方式来进行越界检查。