20155219 2017-2018-1 《信息安全系统设计》第3周学习总结
教材学习内容总结
信息的表示和处理
三种数字表示
-
无符号数:基于传统的二进制表示法,表示大于或等于零的数字
-
补码:表示有符号数,可为正可为负的数字
-
浮点数:表示实数的科学计数法的以二为基数的版本
-
整数运算和浮点数运算有不同的数学属性,因为它们处理数字表示有限性的方式不同,整数的表示虽然只能编码一个相对较小的数值范围,但这种表示精确;浮点数编码数值范围相对较大,但是近似的。
-
大量计算机的安全漏洞都是由计算机算术运算的微秒细节引发的
-
进制转换:二进制、八进制、十进制、十六进制(转换:以二进制作为中间变量)。十六进制:以0x或0X开头表示,字符A-F可大写、可小写、也可混用。
-
字节顺序:有小端、大端两种字节顺序。小端法:指低字节数据存放在内存低地址处,高字节数据存放在内存高地址处。
大端法:是高字节数据存放在低地址处,低字节数据存放在高地址处。 -
逻辑运算
逻辑与(&&):遇0为0;
逻辑或(||):遇1为1;
逻辑非 (!):遇0为1,遇1为0;
- 位运算
按位与(&):二进制每一位遇0为0;
按位或(|):二进制每一位遇1为1;
按位异或():00=0,01=1,10=1,1^1=0;
按位取反(~):二进制每一位取反。
- 掩码:位运算的重要应用,表示从一个字中选择一个位的集合。对特定位可以置一,可以清零。
补码
(1)二进制补码范围是不对称的:|TMin|=|TMax|+1,不存在与最小值相对应的整数,容易造成程序的中细微的错误。
(2)在位数相同的前提下,无符号数的最大值刚好是二进制补码最大值的2倍加1。
(3)二进制补码中的-1与UMax有相同的位表示全1位串。
1、算术运算溢出
完整的整数结果无法放到数据类型的字长限制中。
执行C程序时,不会将溢出作为错误而发出警告信号。
判断无符号运算是否溢出,例如s=x+y(s、x、y均为无符号数),唯一可靠的判断标准就是s<x或s<y。
教材学习中的问题和解决过程
- xx1问题:p49页的有符号数和无符号数互相转换的代码:
#include "stdio.h"
void main(){
short int v=-12345;
unsigned short uv=(unsigned short)v;
printf("v=%d,uv=%u\n",v,uv);
unsigned u=4294967295u;
int tu=(int)u;
printf("u=%u,tu=%d\n",u,tu);
}
中得到的结果如图:
- 1解决方案:-12345的16位补码表示与53191的16位无符号数表示的完全一样,改变了数值不改变位表示。
而第二个函数,是因为无符号数4294967295和补码形式的-1完全相同故将unsigned强制类型转化成int,底层的位表示保持不变。
-
2问题:在p33页处有如下问题:对数值12345编码,整型为0x00003039,而浮点数为0x4640E400
-
2解决方案:通过看狄维佳同学的博客我发现我还是不能很好地理解浮点数的编码,故上网搜索到浮点数在计算机中的编码解决了疑惑。更好的理解了,
因为12345的二进制表示为[11000000111001],将二进制小数点左移13位,得到规格化表示:12345=$1.1000000111001_2 x 2^13$。构造小数字段,需要去掉开头的1,并在末尾添上10个0,得到二进制表示[10000001110010000000000]。构造阶码字段,用13加上偏置量127,得到140,二进制为[10001100]。再加上符号位的0,即得到二进制浮点数表示为01000110010000001110010000000000。
代码调试中的问题和解决过程
- 1问题:运行教材35页change.c代码时,发现代码对于偶数长度的数组能正常工作,但当数组长度为奇数时,中间元素会被设置为0,如图:
代码如下:
#include "stdio.h"
#define MAX 8
void main(){
int a[MAX];
int count,i;
printf("please enter the amount of numbers(no more than %d):\n",MAX);
scanf("%d",&count);
printf("please enter any number as the end:\n");
for(i = 0;i<count;i++){
scanf("%d\n",&a[i]);
}
printf("the original array is as follow:\n");
for(i = 0;i<count;i++){
printf("%d ",a[i]);
}
reverse_array(a, count);
printf("\n");
printf("the new array is as follow:\n");
for(i = 0;i<count;i++){
printf("%d ",a[i]);
}
printf("\n");
}
void inplace_swap(int *x,int *y){
*y=*x^*y;
*x=*x^*y;
*y=*x^*y;
}
void reverse_array(int a[],int cnt){
int first,last;
for(first=0,last=cnt-1;first < last;first++,last--)
inplace_swap(&a[first],&a[last]);
}
如下图所示:
- 1解决方案:调试的时候发现由于在最后一次调用inplace_swap的时候,赋值给first和last变量的都是原数组中中间的数字,所以在第一处*y = x^y 时,y指向的数字变为了0,此后,0作为最中间数字进入了循环。因此把change.c代码中循环条件改为first<last即可。
最后得到正确的输出如下图所示:
家庭作业:
**2.61:
A.!~x
B:!x
C:!~(x>>((sizeof(int)-4)))
D:!(x&0xFF)
代码托管
- 代码提交过程截图:
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 95/95 | 1/1 | 8/8 | 学习了gcc与gdb的使用 |
第二周 | 95/95 | 1/1 | 12/20 | 学习了myod相关内容 |
第三周 | 95/95 | 1/1 | 12/32 | 学习了信息的表示和处理 |
尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。
-
计划学习时间:10小时
-
实际学习时间:12小时
-
改进情况: