如何正确的写加减乘除函数

有符号数加减法,存在溢出问题,经常被用于攻击构造。那么如何编写一个可以防止溢出的“正确的”函数呢?

加法运算

错误写法

signed int func(signed int a, signed int b) {
	return a + b;
}

分析:a与b相加可能溢出(又分为上溢和下溢)
上溢条件:a + b > INT_MAX
下溢条件:a + b < INT_MIN
正确写法

signed int func(signed int a, signed int b)
{
	if (((b > 0) && (a > INT_MAX - b)) || 
		((b < 0) && (a < INT_MIN - b))) {
		/* Handle error */
	} else {
		return a + b;
	}
}

减法运算

错误写法

signed int func(signed int a, signed int b)
{
	return a - b;
}

正确写法

signed int func(signed int a, signed int b)
{
	if ((b > 0 && a < INT_MIN + b) ||
		(b < 0 && a > INT_MAX + b)) {
		/* Handle error */
	} else {
		return a - b;
	}
}

乘法

错误写法

signed int func(signed int a, signed int b)
{
	return a * b;
}

正确写法

#include <stddef.h>
#include <assert.h>
#include <limits.h>
#include <inttypes.h>

extern size_t popcount(uintmax_t)
#define PRECISION(umax_value) popcount(umax_value)


signed int func(signed int a, signed int b)
{
	signed long long tmp;
	assert(PRECISION(ULLONG_MAX) >= 2 * PRECISION(UINT_MAX));
	tmp = (signed long long)a * (signed long long)b;
	
	if ((tmp > INT_MAX) || (tmp < INT_MIN)) {
		/* 处理错误 */
	} else {
		return tmp;
	}
}

除法

错误写法

signed int func(signed int a, signed int b)
{
	if (b == 0) {
		/* 处理错误 */
	} else {
		return a / b;
	}
}

正确写法

signed long func(signed long a, signed long b)
{
	if ((b == 0) || ((a == LONG_MIN) && (b == -1))) {
		/* 处理错误 */
	} else {
		return a / b;
	}
}

这里这个(a == LONG_MIN) && (b == -1)的条件非常有意思,要理解为什么这种情况下计算会出错,得理解数在计算机中是如何存储的。

取余

错误写法

signed long func(signed long a, signed long b)
{
	if (b == 0) {
		/* 错误处理 */
	} else {
		return a % b;
	}
}

正确写法

#include <limits.h>

signed long func(signed long a, signed long b)
{
	if ((b == 0) || ((a == LONG_MIN) && (b == -1))) {
		/* 错误处理 */
	} else {
		return a % b;
	}
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值