20145201 《信息安全系统设计基础》第3周学习总结

20145201 《信息安全系统设计基础》第3周学习总结

教材学习内容总结

三种最重要的数字表示:

  • 无符号

  • 补码

  • 浮点数
    运算:

  • 整数运算

  • 浮点运算

整数运算和浮点运算不同:

整数运算只能编码相对较小的范围,但是是精确的;

浮点运算可以编码一个较大的范围,但是是近似的;浮点运算不可结合。

注意:溢出——运算位数的限制

从逆向角度考虑为什么会产生漏洞
大量计算机漏洞都是由于算数运算的微妙细节引发的。比如无符号数、有符号数、浮点数的局限性;无符号数或者有符号数的表示范围有限,而浮点数虽然编码范围大,但是不精确。

信息存储

1.十六进制表示法

常用进制:二进制(B),十进制(D),八进制(O或者Q),十六进制(H)

转换为二进制-十六进制相互转换,二进制的四位数字对应十六进制的一位数字。

同理,二进制与八进制的转化是三位对应一位。

tips:拿二进制作中间结果就好转了

当 n 表 示 成 i + 4 j 的 形 式 , 其 中 0 ≤ i ≤ 3 时 , 我 们 可 以 把 x 写 成 开 头 的 十 六 进 制 数 字 为 1( i = 0 )、2( i = 1 )、 4(i=2)或者 8(i=3)

2.字

字长决定虚拟地址空间的最大大小。字长为w,虚拟地址的范围为0~(2^w-1)

3.数据大小

gcc -m32 可以在64位机上生成32位的代码

4.寻址和字节顺序

1).小端法和大端法

小端法:最低有效字节在前面——“高对高,低对低”
大端法:最高有效字节在前面

2).强制类型转换

书28页代码

5.布尔代数

常用运算符号:

与: &
或: |
非: ~
异或:^

位向量

位向量:有固定长度为w、由0和1组成的串。
位向量的应用——表示有限集合。
布尔运算 | 和 & 分别对应于集合的并和交,而 ~ 对应于于集合的补。

6.位级运算

位运算:位向量按位进行逻辑运算,结果仍是位向量(区别于逻辑运算)
常见用法:掩码——用来选择性的屏蔽信号

位级表达式
位级表达式的计算,要将通过转化为二进制表示进行二进制运算再转换回原来的进制来进行。

~0:生成一个全1的掩码。

7.逻辑运算

逻辑运算的计算方法:
所有非零参数都代表TRUE,0参数代表FALSE

逻辑运算的结果:
1-代表TRUE,或者,0-代表FALSE

逻辑运算和位运算的区别:

  • 只有当参数被限制为0或1时,逻辑运算才与按位运算有相同的行为。
  • 如果对第一个参数求值就能确定表达式的结果,逻辑运算符就不会对后面的参数求值。

8.移位运算

一般而言,机器支持两种形式的右移:逻辑右移和算术右移。逻辑右移在左端补k个 0,算术右移是在左端补k个最高有效位的值。

C 语言标准并没有明确定义应该使用哪种类型的右移。对于无符号数据(也就是以限定词 unsigned 声明的整型对象),右移必须是逻辑的。而对于有符号数据(默认的声明的整型对 象),算术的或者逻辑的右移都可以。

几乎所有的编译器 / 机器组合都对有符号数据使 用算术右移,且许多程序员也都假设机器会使用这种右移。

另一方面,Java 对于如何进行右移有明确的定义。表达式 x>>k 会将 x 算术右移 k 个位置, 而 x>>>k 会对 x 做逻辑右移。

整数表示

1.整型数据类型
整型数据类型——表示有限范围的整数,每种类型都能用关键字来指定大小,还可以指定是非负数(unsigned)还是负数(默认)。这些不同大小的分配的字数会根据机器的字长和编译器有所不同。

要用C99中的“long long”类型,编译是要用 gcc -std=c99

2.无符号数的编码
注意无符号数的二进制表示的一个重要性质:每个介于0~2^w-1之间的整数都有唯一一个w为的值编码,函数为一个双射。

即0-(2^w)-1中的每一个整数和长度为w的位向量是一一对应的。

3.补码编码(有符号数的编码)

关于补码:将字的最高有效位解释为负权。
有符号数的其他表示方法:
原码
反码

4.有符号数和无符号数的转换

强制类型转换

从位级角度考虑。

强制类型转换的结果保持位值不变,只是改变了解释这些位的方式。即:这些位上的值不变,但是由于最高有效位的权重发生变化,从而导致结果发生改变。

5.c语言中的有符号数和无符号数及其转换

转换原则:底层的位保持不变。

6.扩展一个数字的位表示

扩展——从一个较小的数据类型转换为较大的数据类型,同时保持数值不变。

1).零扩展

将一个无符号数转换为一个更大的数据类型。只需在开头加上0即可。

2).符号扩展

将一个补码数字转换为一个更大的数据类型。最高有效位是什么,就添加什么。

7.截断数字

不用额外的位来扩展数值,而是减少表示一个数字的位数。而这么做可能会改变它的值,这也是溢出的一种形式。

将一个w位的数截断为k位数字时,就会丢弃高w-k位。

对于无符号数x来说,截断它到k位的结果就相当于计算 xmod (2^k)

对于有符号数来说,先按照无符号数截断,然后再转化为有符号数。

整数运算

1.无符号加法 本质上就是模运算,mod 2的w次幂。

考虑两个非负整数x和y,满足0≤x, y≤2w-1。每个数都能表示为w位无符号数字。然而,如果计算它们的和,我们就有一个可能的范围0≤x + y≤2w+1-2。表示这个和可能需要w + 1位。这种持续的“字长膨胀”意味着,要想完整地表示算术运算的结果,要对字长做限制。

算数运算溢出:一个算术运算溢出,是指完整的整数结果不能放到数据类型的总长限制中去。

2.补码加法

两个数的w位补码之和与无符号之和有完全相同的位级表示。

溢出

补码加法的溢出情况比无符号运算更为复杂,分为正溢出、正常、负溢出。正溢出就是超过正数的最大范围,负溢出就是超过负数的最大范围。

但本质仍然是模运算,模掉w位的补码最高有效位的权重2的w次幂。

3.补码的非
(1)补码的非运算

4.无符号乘法
范围在0≤x, y≤ 2w-1内的整数x和y可以表示为w位的无符号数,但是它们的乘积x · y的取值范围为0到(2w-1)2 = 22w-2w+1+1之间。这可能需要2w位来表示。不过,C语言中的无符号乘法被定义为产生w位的值,就是2w位的整数乘积的低w位表示的值。可以看作等价于计算乘积模2w。

5.补码乘法
c语言中的有符号乘法是通过将2w位的乘积截断为w位的方式实现的。也就是说,需要mod 2的w次幂。
所以,对于无符号和补码乘法来说,乘法运算的位级表示都是一样的。

6.乘以常数

在机器运算中,乘法总是很慢的,而加法和移位(左移)是相对较快的。所以在编译器中,会使用移位和加法运算组合的方式来代替乘以常数因子。这种方法对于无符号运算和补码运算都是适用的。

7.除以2的幂

机器运算中,除法比乘法更慢。当被除数为2的整数次幂时,通过右移来解决。右移时需要区分无符号数和补码。

需要注意:整数除法总是舍入到零

1).无符号数——逻辑右移

无符号数除以2的k次幂,就等同于对其逻辑右移k位。

2).补码——算术右移

补码进行算术左移时,需要考虑补码数的正负,因为整数除法总是舍入到零,无符号数中没有负数不必担心,但补码中有正有负,正数向下舍入到零,负数应该向上舍入到零。所以这里涉及到在移位前偏置。
也就是说:

x≥0时,除以2的k次幂等价于将x算术右移k位
x<0时,先将x加上(2^k)-1,再算术右移k位
与乘法不同,这种右移方法不能推广到任意常数C。

8、整数运算的总结

计算机执行的“整数运算”实际上是一种模运算。
无论运算数是以无符号形式还是补码形式表示,都有完全一样或者非常类似的位级行为。
谨慎使用unsigned数据类型,很可能会造成漏洞。

浮点数

浮点表示对形如V=x X (2^y)的有理数进行编码,对执行:
非常大的数字
非常接近于0的数字
作为实数运算的近似值
很有用

1、二进制小数

小数的二进制表示法只能表示那些能够被写成x X (2^y)的数,其他的值只能近似的表示。

权重:
以小数点为界,
左边第i位,权重为2的i次幂
右边第i位,权重为2的-i次幂

2、IEEE浮点表示

IEEE浮点标准用V=(-1)^s ×M× 2^E 来表示一个数:
符号:s决定这个数是正还是负。0的符号位特殊情况处理。
阶码:E对浮点数加权,权重是2的E次幂(可能为负数)
尾数:M是一个二进制小数,范围为12-ε或者01-ε(ε=1/2的n次幂)

编码规则:
单独符号位s编码符号s,占1位
k位的阶码字段exp编码阶码E
n位小数字段frac编码尾数M(同时需要依赖阶码字段的值是否为0)

两种精度:
单精度(float),k=8位,n=23位,一共32位;
双精度(double),k=11位,n=52位,一共64位。

三种被编码情况:(p70)
规格化的
非规格化的
特殊值

  • 规格化的值
    当exp的位模式既不全为0(数值0),也不全为1(单精度数值为255,双精度数值为2047)时,都属于这类情况。在这种情况中,阶码字段被解释为以偏置(biased)形式表示的有符号整数。也就是说,阶码的值是E = e-Bias,其中e是无符号数,其位表示为ek-1…e1e0,而Bias是一个等于2k-1-1(单精度是127,双精度是1023)的偏置值。由此产生指数的取值范围,对于单精度是-126~+127,而对于双精度是-1022~+1023。

  • 非规格化的值
    当阶码域为全0时,所表示的数就是非规格化形式。在这种情况下,阶码值是E = 1 - Bias,而尾数的值是M = f,也就是小数字段的值,不包含隐含的开头的1。非规格化值要这样设置偏置值的原因是使阶码值为1-Bias而不是简单的-Bias似乎是违反直觉的。我们将很快看到,这种方式提供了一种从非规格化值平滑转换到规格化值的方法。

(1)阶码

阶码E = 1-Bias

(2)尾数

尾数M = f(小数字段的值,不包含隐含的1)

(3)非规格化的功能:

提供了一种表示数值0的方法
表示那些非常接近零的数。逐渐溢出。

  • 特殊值

特殊值是在阶码位全为1的时候出现的。当小数域全为0时,得到的值表示无穷,当s = 0 时是+∞,或者当 s = 1时是-∞。当我们把两个非常大的数相乘,或者除以零时,无穷能够表示溢出的结果。

3.舍入

因为表示方法限制了浮点数的范围和精度,浮点运算只能近似地表示实数运算。因此,对于值x,我们一般想用一种系统的方法,能够找到“最接近的”匹配值x',它可以用期望的浮点形式表示出来。

IEEE浮点格式定义了四种不同的舍入方法:

  • 向偶舍入(默认方法)

即:将数字向上或向下舍入,是的结果的最低有效数字为偶数。

能用于二进制小数。

  • 向零舍入

即:把整数向下舍入,负数向上舍入。

  • 向下舍入

正数和负数都向下舍入。

  • 向上舍入

正数和负数都向上舍入。

默认的(即向偶舍入)方法可以得到最接近的匹配,其余三种可用于计算上界和下界。

四舍六入,五求偶。

4.浮点运算

IEEE标准指定了一个简单的规则,用来确定诸如加法和乘法这样的算术运算的结果。把浮点值x和y看成实数,而某个运算⊙定义在实数上,计算将产生Round (x ⊙ y),这是对实际运算的精确结果进行舍入后的结果。当参数中有一个是特殊值(如-0、-∞或NaN)时,IEEE标准定义了一些使之更合理的规则。例如,定义1/-0将产生-∞,而定义1/+0会产生+∞。

浮点加法不具有结合性,这是缺少的最重要的群属性。
浮点加法满足了单调性属性:如果a≥b,那么对于任何a、b以及x的值,除了NaN,都有x + a ≥ x + b。无符号或补码加法不具有这个实数(和整数)加法的属性。
对于任何a、b和c,并且a、b和c都不等于NaN,浮点乘法满足下列单调性:

5、c语言中的浮点数

所有的C语言版本提供了两种不同的浮点数据类型:float和double。在支持IEEE浮点格式的机器上,这些数据类型就对应于单精度和双精度浮点。
较新版本的C语言,包括ISO C99,包含第三种浮点数据类型long double。对于许多机器和编译器来说,这种数据类型等价于double数据类型。不过对于Intel兼容机来说,GCC用80位“扩展精度”格式来实现这种数据类型,提供了比标准64位格式大得多的取值范围和精度。

int、float、double相互转换

int → float 不会溢出但有可能舍入
int/float → double 结果保留精确数值
double → float 可能溢出为±∞,由于精确度较小也有可能被舍入
float/double → int 向零舍入,可能溢出。

教材学习中的问题和解决过程

p48怎么样让负数等于正数?
由练习题2.21在负数x后加上U,可以使其转换为(2^w+x)

课后作业中的问题和解决过程

(p35)2.13
问题:假设有两个函数bis和bic来实现位设置和位清除操作;只利用这两个函数实现按位 | 和^操作。

int bis(int x, int y);
int bis(int x, int y);

int bool_or(int x,int y)
{
    int result = bis(x,y);
    return result;
}
int bool_xor(int x,int y)
{
    int result = bis(bic(x,y),bic(y,x));
    return result;
}

解答: x^y = (x&~y) | (~x&y)知识点要掌握

问题:(p51)2.23

#include<stdio.h>
int fun1(unsigned word)
{
    return (int)((word<<24)>>24);
}
int fun2(unsigned word)
{
    return ((int)word<<24)>>24;
}

解决:
fun1()将word进行逻辑左移和右移后的结果转换为int型;
fun2()是将word先强制转换为int型,再进行的算数左移和右移。

w:0x87654321 fun1(w)=0x00000021,fun2(W)=0x00000021 (先进行左移即右侧六个十六进制位补f,之后右移的时候,因为最高有效位是0,所以前侧六个十六进制位补0)

(p52)2.25

解决:

以正常的浮点数数组输入,得到正常结果,但是输入0时有报错,如图:

解释:原因应该在“i<=length-1”与之前声明的“unsigned length”的矛盾中。因为当输入的length是0时,length-1=0-1(无符号数运算),即模数加法,得到的是Umax。而任何数都是小于Umax的,所以比较式恒为真。则循环会访问数组a中的非法元素。简单的处理办法就是将length声明为int型

本周代码托管截图

代码链接

其他(感悟、思考等,可选)

这次以书上第二章内容为主,按照老师罗列的重点一一学习。关于这章的内容,很多知识都是看起来很熟悉,我们都曾学习过或者接触过,重点还是需要应用到实践中,都需要练习。这周主要看的是练习题,对于枯燥的文字知识,还是题目解答能让我们理解更深刻,更明确。但在做题过程中,公式也是很重要的,也需要翻回头重点看相关公式。

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 5000行 30篇 400小时
第一周 100/100 2/2 25/25 安装了虚拟机并学习掌握核心的linux命令
第二周 100/200 1/3 30/55 虚拟机上的C语言编程
第三周 150/350 1/4 10/65 计算机中信息的表示和运算

参考资料

posted @ 2016-10-02 21:23  20145201李子璇  阅读(190)  评论(2编辑  收藏  举报