C语言数据类型重新认识
2014-08-12 19:23
260 查看
注:本篇文章是对《深入理解操作系统》这本书的笔记。
无符号运算:
以一个四位数字表示,x=9,y=12;分别是1001 和1100,它们的和是21,相加后5位表示为10101,但是如果丢弃最高位,我们就得到了0101也就是十进制的5,他就和21mod15的值一样了。是否溢出是看和的最高位w+1是否被置1,如果等于0,和原来4位一样丢弃也没有影响。如果溢出相当于从和减去16.
对于一个w位的数判断是否溢出的方法,
设s=x+y;
0<=x<=2^w-1;
0<=y<2^w-1;
所以0<=s<=2^(w+1)-2;
我们要判断s是否等于x+y,因为如果正常s=x+y>=x,如果s确实溢出了,s=x+y-2^w,假设y<2^w,我们就有y-2^w<0,因此s=x+(y-2^w)<x.,即s<x或者s<y的时候就可以了.
补码加法:
给定:-2^w-1<=x,y<=2^w-1之内 整数值,他们的和就在范围-2^w<=x+y<=2^w-2之内。要准确表示可能需要w+1位,我们通表示截断到w位,来避免数据大小的扩张,然而结果却不像模数加法那样熟悉。
还是以4位数的为例子。
一共有四种情况:
x y x+y 截断后结果 情况
-8[1000] -5[1011] -13[10011] 3[0011] 1
-8[1000] -8[1000] -16[10000] 0[0000] 1
-8[1000] 5[0101] -3[11101] -3[1101] 2
2[0010] 5[0101] 7[00111] 7[0111] 3
5[0101] 5[0101] 10[01010] -6[1010] 4
当w=4的补码加法,运算数的范围是-8~7,当x+y<-8的时候,补码加法会负溢出,导致和增加了16,当-8
<x+y<8的时候,加法就产生x+y。当x+y>=8的时候,会正溢出,使得结果减少了16。
判断是否溢出,无符号整数。
//在int tadd_ok_2(char x,char y)不成立的前提下无法理解用除法判断乘法溢出,并且无法看懂解释:
1:说明x和y的乘积x*y可以写成x*y=p+t*2^w;,其中t不等于0,当且仅当p的计算溢出。
2.说明p可以写成这样形式:p=x*q+r|r|<|x|;
3.说明q=y当且仅当r=t=0;
乘法溢出漏洞案例:
Sun Microsystems公司的XDR。
代码
函数copy_elements的设计上将ele_cnt个数据结构复制到申请得到的数据缓冲区内,每个函数结构包含了ele_size个字节,需要的字节是通过ele_cnt*ele_size得到的。
如果怀有恶意的人把参数ele_cnt等于1048577(2^20+1)ele_size等于(2^12)4096,来调用这个函数,然后乘法上会溢出,导致只分配4096个字节而不是装下这些数据所需要的
4294971392个字节,从循环开始的会试图复制所有字节,超越已经分配的缓冲区的界限,因而破坏了其他的数据结构,导致程序崩溃或者行为异常。
修复代码:
修复代码的后面三句至关重要,删除后没有作用,malloc调用的时候会把longlong
unsigned 当成一个32位的无符号数。还是溢出。
无符号运算:
以一个四位数字表示,x=9,y=12;分别是1001 和1100,它们的和是21,相加后5位表示为10101,但是如果丢弃最高位,我们就得到了0101也就是十进制的5,他就和21mod15的值一样了。是否溢出是看和的最高位w+1是否被置1,如果等于0,和原来4位一样丢弃也没有影响。如果溢出相当于从和减去16.
int uadd_ok(unsigned char x,unsigned chary) { unsigned char s=x+y; printf("%d ",s); printf("%d",s>=x) ; }
对于一个w位的数判断是否溢出的方法,
设s=x+y;
0<=x<=2^w-1;
0<=y<2^w-1;
所以0<=s<=2^(w+1)-2;
我们要判断s是否等于x+y,因为如果正常s=x+y>=x,如果s确实溢出了,s=x+y-2^w,假设y<2^w,我们就有y-2^w<0,因此s=x+(y-2^w)<x.,即s<x或者s<y的时候就可以了.
补码加法:
给定:-2^w-1<=x,y<=2^w-1之内 整数值,他们的和就在范围-2^w<=x+y<=2^w-2之内。要准确表示可能需要w+1位,我们通表示截断到w位,来避免数据大小的扩张,然而结果却不像模数加法那样熟悉。
还是以4位数的为例子。
一共有四种情况:
x y x+y 截断后结果 情况
-8[1000] -5[1011] -13[10011] 3[0011] 1
-8[1000] -8[1000] -16[10000] 0[0000] 1
-8[1000] 5[0101] -3[11101] -3[1101] 2
2[0010] 5[0101] 7[00111] 7[0111] 3
5[0101] 5[0101] 10[01010] -6[1010] 4
当w=4的补码加法,运算数的范围是-8~7,当x+y<-8的时候,补码加法会负溢出,导致和增加了16,当-8
<x+y<8的时候,加法就产生x+y。当x+y>=8的时候,会正溢出,使得结果减少了16。
判断是否溢出,无符号整数。
//有符号型判断。 int tadd_ok(char x,char y) { //这是答案 答案的数据类型为整形。 char sum=x+y; intneg_over=x<0&&y<0&&sum>0=0; intpos_over=x>=0 && y>=0 && sum<0; return!neg_over && !pos_over; } int tadd_ok_2(char x,char y) { //答案说这个不行,我试了下可以的,答案的类型是整形 //阿贝尔群知识不懂 char sum=x+y; return (sum-x==y)&&(sum-y==x); } void inplace(int *x,int*y)//交换两个变量的值,不用临时变量 { *y=*x^*y; *x=*x^*y; *y=*x^*y; }//不可自己交换自己否则得0 void reverse_array(int a[],int cnt) { intfirst,last; for(first=0,last=cnt-1;first<=last;first++,last--) { voidinplace(&a[first],&a[last]); } } /*上面这个函数包含元素个数为偶数个的时候可以,奇数不可以,奇数时候最后一次交换中间值本身,inplace函数中运算会的到0,所以把first<=last改成first<last.*/ //检验乘法是否溢出 int tmult_ok(int x,int y) { intp=x*y; return!x || p/x==y; }
//在int tadd_ok_2(char x,char y)不成立的前提下无法理解用除法判断乘法溢出,并且无法看懂解释:
1:说明x和y的乘积x*y可以写成x*y=p+t*2^w;,其中t不等于0,当且仅当p的计算溢出。
2.说明p可以写成这样形式:p=x*q+r|r|<|x|;
3.说明q=y当且仅当r=t=0;
//这个函数对于数据类型为int 的32位情况,使用64位精度数据类型long long 而不使用除法。 int tmult_ok_2(int x,int y) { longlong pll =(long long )x*y; returnpll==(int)pll; }
乘法溢出漏洞案例:
Sun Microsystems公司的XDR。
代码
void *copy_elements(void *ele_src[],intele_cnt,size_t ele_size) { void *result=malloc(ele_cnt *ele_size); if(result==NULL) return NULL; void *next=result; int i; for(i=0;i<ele_cnt;i++) { memcpy(next,ele_src[i],ele_size); next+=ele_size; } return result; }
函数copy_elements的设计上将ele_cnt个数据结构复制到申请得到的数据缓冲区内,每个函数结构包含了ele_size个字节,需要的字节是通过ele_cnt*ele_size得到的。
如果怀有恶意的人把参数ele_cnt等于1048577(2^20+1)ele_size等于(2^12)4096,来调用这个函数,然后乘法上会溢出,导致只分配4096个字节而不是装下这些数据所需要的
4294971392个字节,从循环开始的会试图复制所有字节,超越已经分配的缓冲区的界限,因而破坏了其他的数据结构,导致程序崩溃或者行为异常。
修复代码:
long long unsignedrequired_size=ele_cnt*(long long unsigned)ele_size; size_t request_size=(size_t)required_size; if(request_size!=required_size) return NULL;
修复代码的后面三句至关重要,删除后没有作用,malloc调用的时候会把longlong
unsigned 当成一个32位的无符号数。还是溢出。
相关文章推荐
- C语言 第二讲 数据类型
- c语言(第一次上机资料,数据类型讲课资料)
- 认识oracle数据类型
- C语言提供的合法的数据类型关键字是
- 在学C语言之第二章C语言的基本数据类型和存储类-------双精度型数据
- C语言中的数据类型在VB中的申明
- 第二章 C语言的数据类型
- 认识JDBC 2.0中的高级数据类型
- C语言的数据类型
- C语言中各种数据类型长度的总结
- (C语言教程)第二章: 数据类型、运算符、表达式
- C语言的基本数据类型(9)
- 嵌入式系统开发人员C语言测试题--填空题(数据类型和变量)
- GTK中的数据类型与C语言的数据类型
- [转]认识oracle数据类型
- C语言之数据类型
- C语言一些基础:数据类型,运算类型及表达式
- 重新认识表格和一个访问无障碍的数据表格例子
- 在学C语言之第二章C语言的基本数据类型和存储类-------字符型数据
- C语言 第七章 高级数据类型(3):位运算符和位域