整数的表示虽然只能编码一个相对较小的数值范围,但是这种表示是精确的
浮点数虽然可以编码一个较大的数值范围,但是这种表示只是近似的
unix和c都是出自贝尔实验室,unix绝大部分代码也是用c语言编写的
c语言中一个指针的值,都是某个存储快的第一个字节的虚拟地址。c编译器还把每个指针和类型信息联系起来,这样就可以根据指针值的类型,生成不同的机器级代码来访问存储在指针所指向位置处的值
十进制314156转换成十六进制:
314156=19634x16+12 (C)
19634=1227x16+2 (2)
1227=76x16+11 (B)
76=4x16+12 (C)
4=0x16+4 (4)
所以十六进制表示为0x4CB2C
十进制转十六进制,0xAF
AX16+F=175
对于变量(char ,short int,int,long int,long long int,char*,float,double)的声明:
对于32位机器long int为4字节,char*为4字节
对于64位机器long int为8字节,char*为8字节
其他的32位与64位没区别,分别是char 1,short int 2,int 4,long long int 8,float 4,double 8
大端与小端法:
假设int类型的变量x,位于地址0x100处,它的16进制数为0x01234567,地址范围为0x100到0x103之间,排列顺序依赖于机器类型
大端法:
0x100 0x101 0x102 0x103
01 23 45 67
小端法:
0x100 0x101 0x102 0x103
67 45 23 01
机器支持两种形式的右移:逻辑右移和算数右移,逻辑右移是在左端补k个0,算数右移是在左端补k个最高有效位的值,c语言标准把那个没有明确定义应该使用那种类型的右移,然而实际上,几乎所有的额编译器/机器组合都对有符号数据使用算数右移,且许多程序员也都假设机器会使用这种右移
当移位的位数大于机器字长时,也就是假设在32位机移位33位时,会怎样?
c标准情况下,移位应该是33mod32为1,所以移动1位,不过这种行为对于c程序来说设没有保证的,所以移位数量应该保持小于字长
加减法的运算优先级高于移位运算,所以这里常常会出错,如果拿不准最好加括号!
整数与浮点数表示:
c和c++都支持有符号(默认)和无符号数。java只支持有符号数
对于有符号数和无符号数表达式的这种处理方式,出现了一个奇特的行为。当执行一个运算时,如果它的一个运算数是有符号的而另一个是无符号的,那么c预压1会隐式的将有符号参数强制类型转换成无符号数,并假设这两个数都是非负的,来执行这个运算,这个结果当进行>或<运算时,就有可能是错误的。
从一个数据到另一个数据大小的转换,以及无符号和有符号数字之间的转换的相对顺序能够影响一个程序的行为,例如把short转换成unsigned时,我们要先改变大小,之后在完成有符号到无符号之间的转换先从2个字节转换成4个字节,然后再从有符号转换成无符号。
原码反码补码:
简便算法:正数按位取反+1得负数
我们根据有符号和无符号的这些发现,推出了一个安全隐患,下面是FreeBSD2002年getpeername函数的安全漏洞:
14行开始的函数copy_from_kernel是要将一些操作系统内核维护的数据复制到指定的用户可以访问的存储器区域,正常不可能让普通用户得到内核数据的,但是显示为kbuf的区域是用户可以读的。maxlen是分配给用户的缓冲区长度,16行保护他的大小最大不超过1024,但是如果黑客构造一个负数来填入maxlen,小于1024,但最后转化为size_t的无符号整形,比1024大,就可以造成缓冲区溢出!
我们避免这一漏洞的一种方法就是绝不使用无符号数,实际上除了C以外,很少有语言支持无符号整数,所以在我们进行漏洞挖掘时,可以多关注一下有符号数与无符号数之间的转换可不可能绕过。
有符号数的益处:当我们想要把字仅仅看作是位的集合,并且没有任何数字意义时,无符号整形石粉厂有用的。当实现模运算和多精度运算的数学包时,数字是由字的数组来表示的,无符号也会非常有用!
乘法造成溢出产生系统崩溃:这里我还没搞懂,放在这里以后填坑:
整数运算的最后思考:
正如我们看到,计算机执行的“整数”运算实际上是一种模运算形式。表示数字的有限字长限制了可能的值的取值范围,结果运算可能溢出。我们还看到,补码表示提供了一种不过既能表示负数也能表示正数的灵活方法,同时使用了与执行无符号算数相同的位级实现,这些运算包括加法,减法,乘法甚至除法,无论运算数是以无符号形式还是以补码形式表示的,都有完全一样或者非常类似的位级行为。