在高级语言中,两个n位整数相乘得到的结果通常也是一个n位整数,即结果只取2n位乘积中的低n位。这导致乘法运算得到结果必须在范围: -2n-1<= x*y < 2n-1才不会溢出。
假设为4位,进行52
0101
* 0101
--------
0101
+ 0101
-------- 只取4位,即1001 为1111的补码 即为-7
00011001
----
在二进制乘法运算下,只有1*1等于1;
再列如:32
0011
* 0011
--------
0011
+ 0011 1001同样为1001 也为-7的补码
--------
00001001
----
运算溢出会给程序带来意想不到的结果
int mult(int x,int y){
int z=x*y;
if(!x||z/x==y) return z;
//这样的设计能避免溢出得到错误的数据
}
注意:
1、当x、y、z都是unsigned int时,只需要根据乘积的高n位是否为全0,进行判断溢出,全为0,则不溢出。
这与unsigned的特性有关,因为它无负数,故最高位的符号位也充当存储数值的功能。如果是一个n位的乘法,它的取值范围只能:0~2n-1之间,然而进行n位的乘法会得到一个2n位的数据,而乘法的结果只保留低n位,故在不溢出的情况下,高n位只能全为0.
2、若高n位全为0或全为1且等于低n位的最高位,则不溢出。
在MIPS处理器中,mult会将两个32位带符号整数相乘,得到的64位乘积置于两个32位内部寄存器Hi和Lo中,因此,可以根据Hi寄存器中的每一个位值是否等于Lo中的最高位进行溢出判断。
注:乘法指令不产生溢出标志
整数乘法溢出漏洞
int copy_array(int* array,int count){
int *myarray=(int*)malloc(count*sizeof(int));
if(myarray==NULL){
return -1;
}
for(int i=0;i<count;i++)
myarray[i]=array[i];
return count;
}
当参数count很大时,则count*sizeof(int)会溢出。
malloc会在堆一段能容纳需要大小的连续空间分配,在进行越出访问时,可能会破坏堆(heap)中的大量数据。
整数乘法运算比较移位和加法等运算所用时间长,,因此,编译器在处理变量与常数相乘时,往往以移位、加法和减法的组合运算来代替乘法运算。
例如:对于表达式x20,编译器可以利用 20=16+4=24+22,将x20转换为(x<<4)+(x<<2),这样,一次乘法转换两次移位和一次加法。