为什么要考虑四则运算的数据安全性?如果没有考虑会有什么样的危险?
首先,数学是一个纯粹的逻辑学科,比如一个数字的运算。1 + 1 = 2 这在逻辑运算中绝对正确。
但是,在计算机中所有的数据都由寄存器中的 0 1 来表示,所以对于计算机中数字的背后都会有一个数据类型的限制。
如果,极端一点,我们针对 1 + 1 中的 1 是由 1bit 为单位的数据类型,那么在计算机运算中会发现 1 + 1 = 0 。
同理,针对最常见的8位无符号类型(Uint8_t)数据,在 A + B <= 0xffu 时,数据是安全的,可是当 A + B > 0xffu 运算所得结果就会受到数据类型限制。
所以,在本文中针对常见的整数类型四则运算的安全性提出一套解决方法。
整数加法// 以32位无符号数字为例,该类型最大值为 0xffffffffu
// 所以,一个参数 a 可被加的值应该为 0xffffffffu - a
// 在计算机中利用位取反操作实现上述可加值的范围检测
Bool UInt32Add(UInt32 a, UInt32 b, UInt32* value)
{
*value = a + b;
return a <= ~b;
}
// 当数据类型为有符号计算时,可利用结果 与 参数的极性判断结果是否有效
// 当参数 a b 为异号,在该情况下结果回向 0 趋近所以不会发生结果越界的情况
// 当参数 a b 为同号,在该情况下如果结果和参数的符号不一致 即可判定结果已经越界
// 在计算机中最高位为符号位利用异或位运算即可判断两个整形是否异号
Bool Int32Add(int a, int b, int* val)
{
*val = a + b;
return (a ^ b) < 0 || (*val ^ a) >= 0;
}
整数乘法
// 以32位无符号数字,该类型最大值为 0xffffffffu
// 沿用加法时的思想,通过判断 参数a 是否在 参数b 的安全乘数范围,从而确定两者相乘是否安全
Bool UInt32Mul(UInt32 a, UInt32 b, UInt32* value)
{
Bool result = True;
if (a == 0 || b == 0)
*value = 0;
else if (a <= 0xffffffffu / b)
*value = a * b;
else
result = False;
return result;
}
// 同样沿用加法思想,但是在乘操作时最高位为符号位,所以32位有符号位的绝对值等于31位无符号值
Bool Int32Mul(Int32 a, Int32 b, Int32* value)
{
Bool result = True;
if (a == 0 || b == 0)
*value = 0;
else if ((unsigned)(a & 0x7fffffffu) <= 0x7fffffffu / (unsigned)(b & 0x7fffffffu))
*value = a * b;
else
result = False;
return result;
}
整数减法
Bool UInt32Sub(UInt32 a, UInt32 b, UInt32* value)
{
*value = a - b;
return a >= b;
}
// 有符号减法的情况如下表
| 被减数 | 减数 | 结果 |
|---|---|---|
| + | - | + |
| – | – | – |
| - | + | - |
| – | – | – |
| + | + | ± |
| – | – | – |
| - | - | ± |
| – | – | – |
// 通过符号将计算过程分为两种:异号,同号
// 异号相减,有效值的结果一定与被减数同号
// 同号相减,被减数>=减数时 结果>=0, 否则结果<0
Bool Int32Sub(int32 a, int32 b, int32* value)
{
Bool result;
*value = a - b;
// 同号
if ((a ^ b) >= 0)
result = (a >= B && *value >= 0)
|| (a < B && *value < 0);
else // 异号
result = (a ^ *value) >= 0;
return result;
}
整数除法
// 在除法运算中结果绝对值不会超过被除数绝对值,所以不用检查范围
// 只需要注意除数不为零即可
Bool UInt32Div(UInt32 a, UInt32 b, UInt32* value)
{
Bool result = Fasle;
if (b != 0)
{
*value = a / b;
result = True;
}
return result;
}
Bool Int32Div(int32 a, int32 b, int32* value)
{
Bool result = Fasle;
if (b != 0)
{
*value = a / b;
result = True;
}
return result;
}



