计算机以8位为一块(称作字节byte)作为最小的可寻址的内存单位。
虚拟地址空间(virtual address space)
小端表示与大端表示是关于某一个数据在计算机的存储顺序
以字节为单位
布尔代数中,and可用于令特定位为0,or可用于令特定位为1,xor可用于令特定位保持不变。
A xor B = (A&~B) | (~A&B)
其本质含义是,将不同的拿出来。
在C语言中,编译器大多认为对符号数右移为算数右移。
无符号的编码和补码的编码,定义由向量从右到左排列之和。
具有唯一性
宏能保证:无论代码如何被编译的,都能生成正确格式
如printf("x=%" PRId32 ", y=%" PRIu64 "\n",x,y)
C预处理器遇到仅用空格分割的字符串常量序列,就串联起来
反码最高位权重比补码低1
原码最高位表符号
两者都有两个0,一般不采用
补码用2^w - x,表示-x,而反码由直接表示
有符号数与无符号数之间的转换
我们采用二进制作为过渡
补码->无符号数
x + 2^w if< 0
x if> 0
也就是x+X(w-1)2^w*
无符号数->补码(Two's Complement)
u <= TMax(w)
u-2^w > TMax(w)
在C语言中,向无符号靠近。
-1 < 0U 时 为0
2147483647U > -2147483647 - 1 为0
在上述中采用了-2147483647-1。
在宏定义中,主要是因为奇怪的规则。采用了这种方式。
#define INT_MAX 2147483647
#define INT_MIN (-INT_MAX - 1)
零扩展与符号扩展
在C语言中,short->unsigned时,先改变大小,再完成无符号转换
无符号的截断数字是取模
有符号的截断数字是取模后再转为有符号
由于这种强制类型转换会导致错误
getpeername的安全漏洞。
函数void *memcpy(void *dest, void *src, size_t n);复制到用户的缓冲区。
n如果选用负数-->变成size_t的无符号数,可能导致溢出
Java中没有无符号数
无符号加法的溢出
x+y x+y < 2^w
x+y-2^w 2^ <= x+y <2^(w+1)
求反则是2^w-x
检测(x+y)>= x
补码加法的溢出
正溢出:x+y - 2^w(本质:去掉溢出的,再加上符号的负)
正常:x+y
负溢出:x+y + 2^w(只进了1位,变成正的,+上进的,+符号)
对于负溢出
我们先将其转换为无符号数,则+2^w,去掉高处部分,此时符号位为0。
我们要记住的就是:正-->负, 负-->正, 正常-->正常
推导方式,转为无符号,再转回来。
最终表达式x+y = U2Tw[(x+y)mod 2^w]
注:补码取的是-x的表示方法
检测:s==(x+y)当x>0,y>0,s<=0,与x<0,y<0, s>=0
阿尔贝群中加法逆元操作恒成立
补码的非,除了最小值=自己,其他相反
一、非的位级表示,~x+1 与 -x相同。二、从右到左,第一个1,以前取反。
无符号乘法=截断
补码乘法=U2Tw(xymod2^w)*
位级等价性
乘法是否溢出
int tmult_ok(int x, int y){
int p = x*y;
return !x || p/x == y;
}
证明方法:
一、xy = p + t2^w。仅有t>0时,溢出
二、除法时,p=xy+r,xy = xy + r + t2^w,
三、仅当r = t2^w时,原式成立。此时,t=0,不溢出
在这里我们阐明三个问题。
首先,xy=p在t>0时,不满足。
q=y当且仅当t=r=0时成立。
否则q就不等于y,那么也就表明溢出。
补码乘法,本来就是截断的,那么也就意味着,如果乘法发生溢出,那么截断也就出现了问题。
我们要注意的就是,溢出的值使得仍保留在原位的值不再与实际值相同
int tmult_ok(int x, int y){
int64_t pll = (int64_t)x*y;
return pll == (int)pll;
}
这里可以再次说明,乘法的位级等价性,不仅仅用于说明乘积的位级表示相同,还说明,无符号乘积在溢出的判断的意义是和补码是等价的。
void *copy_elements(void *ele_src[]), int ele_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;
}
假如在malloc 处发生溢出,则分配内存不足,导致缓冲区溢出。
乘以常数,利用移位优化。
考虑k的形式 n位到m位都是1
形式A:(x<<n) + (x<<(n-1)) + ...+(x<<m)
形式B:(x<<(n+1)) - (x<<m)
当n = m时,A
当n = m+1,A B同速
当n > m+1,B
除以2的幂
无符号,直接>>
补码,加偏置(y-1)
原因:负数要向0舍入,
x = qy+r, floor((x+y-1)/y) = q+(floor(r+y-1)/y)
C表达式:(x<0 ? x+(1<<k)-1 : x) >> k
写一个函数div16,对于整数参数x返回x/16的值。你的函数使用除法、模运算、乘法、任何条件语句(if或者?:)、任何比较运算符(>、<、==)或任何循环。你可以假设数据类型int是32位字长,使用补码表示,而右移是算术右移。
int div16(int x){
ins bias = (x>>31) & 0xF;
return (x+bias)>>4;
}