計(jì)算機(jī)以8位為一塊(稱作字節(jié)byte)作為最小的可尋址的內(nèi)存單位。
虛擬地址空間(virtual address space)
小端表示與大端表示是關(guān)于某一個(gè)數(shù)據(jù)在計(jì)算機(jī)的存儲(chǔ)順序
以字節(jié)為單位
布爾代數(shù)中,and可用于令特定位為0,or可用于令特定位為1,xor可用于令特定位保持不變叁鉴。
A xor B = (A&~B) | (~A&B)
其本質(zhì)含義是,將不同的拿出來(lái)。
在C語(yǔ)言中,編譯器大多認(rèn)為對(duì)符號(hào)數(shù)右移為算數(shù)右移岗照。
無(wú)符號(hào)的編碼和補(bǔ)碼的編碼,定義由向量從右到左排列之和笆环。
具有唯一性
宏能保證:無(wú)論代碼如何被編譯的谴返,都能生成正確格式
如printf("x=%" PRId32 ", y=%" PRIu64 "\n",x,y)
C預(yù)處理器遇到僅用空格分割的字符串常量序列,就串聯(lián)起來(lái)
反碼最高位權(quán)重比補(bǔ)碼低1
原碼最高位表符號(hào)
兩者都有兩個(gè)0,一般不采用
補(bǔ)碼用2^w - x咧织,表示-x嗓袱,而反碼由直接表示
有符號(hào)數(shù)與無(wú)符號(hào)數(shù)之間的轉(zhuǎn)換
我們采用二進(jìn)制作為過(guò)渡
補(bǔ)碼->無(wú)符號(hào)數(shù)
x + 2^w if< 0
x if> 0
也就是x+X(w-1)2^w*
無(wú)符號(hào)數(shù)->補(bǔ)碼(Two's Complement)
u <= TMax(w)
u-2^w > TMax(w)
在C語(yǔ)言中,向無(wú)符號(hào)靠近习绢。
-1 < 0U 時(shí) 為0
2147483647U > -2147483647 - 1 為0
在上述中采用了-2147483647-1渠抹。
在宏定義中,主要是因?yàn)槠婀值囊?guī)則闪萄。采用了這種方式梧却。
#define INT_MAX 2147483647
#define INT_MIN (-INT_MAX - 1)
零擴(kuò)展與符號(hào)擴(kuò)展
在C語(yǔ)言中,short->unsigned時(shí)败去,先改變大小放航,再完成無(wú)符號(hào)轉(zhuǎn)換
無(wú)符號(hào)的截?cái)鄶?shù)字是取模
有符號(hào)的截?cái)鄶?shù)字是取模后再轉(zhuǎn)為有符號(hào)
由于這種強(qiáng)制類型轉(zhuǎn)換會(huì)導(dǎo)致錯(cuò)誤
getpeername的安全漏洞。
函數(shù)void *memcpy(void *dest, void *src, size_t n);復(fù)制到用戶的緩沖區(qū)圆裕。
n如果選用負(fù)數(shù)-->變成size_t的無(wú)符號(hào)數(shù)广鳍,可能導(dǎo)致溢出
Java中沒(méi)有無(wú)符號(hào)數(shù)
無(wú)符號(hào)加法的溢出
x+y x+y < 2^w
x+y-2^w 2^ <= x+y <2^(w+1)
求反則是2^w-x
檢測(cè)(x+y)>= x
補(bǔ)碼加法的溢出
正溢出:x+y - 2^w(本質(zhì):去掉溢出的,再加上符號(hào)的負(fù))
正常:x+y
負(fù)溢出:x+y + 2^w(只進(jìn)了1位吓妆,變成正的赊时,+上進(jìn)的,+符號(hào))
對(duì)于負(fù)溢出
我們先將其轉(zhuǎn)換為無(wú)符號(hào)數(shù)行拢,則+2^w祖秒,去掉高處部分,此時(shí)符號(hào)位為0舟奠。
我們要記住的就是:正-->負(fù), 負(fù)-->正, 正常-->正常
推導(dǎo)方式竭缝,轉(zhuǎn)為無(wú)符號(hào),再轉(zhuǎn)回來(lái)沼瘫。
最終表達(dá)式x+y = U2Tw[(x+y)mod 2^w]
注:補(bǔ)碼取的是-x的表示方法
檢測(cè):s==(x+y)當(dāng)x>0,y>0抬纸,s<=0,與x<0,y<0, s>=0
阿爾貝群中加法逆元操作恒成立
補(bǔ)碼的非晕鹊,除了最小值=自己松却,其他相反
一、非的位級(jí)表示溅话,~x+1 與 -x相同晓锻。二、從右到左飞几,第一個(gè)1砚哆,以前取反。
無(wú)符號(hào)乘法=截?cái)?/em>
補(bǔ)碼乘法=U2Tw(xymod2^w)*
位級(jí)等價(jià)性
乘法是否溢出
int tmult_ok(int x, int y){
int p = x*y;
return !x || p/x == y;
}
證明方法:
一屑墨、xy = p + t2^w躁锁。僅有t>0時(shí),溢出
二卵史、除法時(shí)战转,p=xy+r,xy = xy + r + t2^w以躯,
三槐秧、僅當(dāng)r = t2^w時(shí),原式成立忧设。此時(shí)刁标,t=0,不溢出
在這里我們闡明三個(gè)問(wèn)題址晕。
首先膀懈,xy=p在t>0時(shí),不滿足谨垃。
q=y當(dāng)且僅當(dāng)t=r=0時(shí)成立启搂。
否則q就不等于y,那么也就表明溢出刘陶。
補(bǔ)碼乘法狐血,本來(lái)就是截?cái)嗟模敲匆簿鸵馕吨缀耍绻朔òl(fā)生溢出匈织,那么截?cái)嘁簿统霈F(xiàn)了問(wèn)題。
我們要注意的就是牡直,溢出的值使得仍保留在原位的值不再與實(shí)際值相同
int tmult_ok(int x, int y){
int64_t pll = (int64_t)x*y;
return pll == (int)pll;
}
這里可以再次說(shuō)明缀匕,乘法的位級(jí)等價(jià)性,不僅僅用于說(shuō)明乘積的位級(jí)表示相同碰逸,還說(shuō)明乡小,無(wú)符號(hào)乘積在溢出的判斷的意義是和補(bǔ)碼是等價(jià)的。
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 處發(fā)生溢出饵史,則分配內(nèi)存不足满钟,導(dǎo)致緩沖區(qū)溢出胜榔。
乘以常數(shù),利用移位優(yōu)化湃番。
考慮k的形式 n位到m位都是1
形式A:(x<<n) + (x<<(n-1)) + ...+(x<<m)
形式B:(x<<(n+1)) - (x<<m)
當(dāng)n = m時(shí)夭织,A
當(dāng)n = m+1,A B同速
當(dāng)n > m+1吠撮,B
除以2的冪
無(wú)符號(hào)尊惰,直接>>
補(bǔ)碼,加偏置(y-1)
原因:負(fù)數(shù)要向0舍入泥兰,
x = qy+r, floor((x+y-1)/y) = q+(floor(r+y-1)/y)
C表達(dá)式:(x<0 ? x+(1<<k)-1 : x) >> k
寫一個(gè)函數(shù)div16弄屡,對(duì)于整數(shù)參數(shù)x返回x/16的值。你的函數(shù)使用除法鞋诗、模運(yùn)算膀捷、乘法、任何條件語(yǔ)句(if或者削彬?:)担孔、任何比較運(yùn)算符(>、<吃警、==)或任何循環(huán)糕篇。你可以假設(shè)數(shù)據(jù)類型int是32位字長(zhǎng),使用補(bǔ)碼表示酌心,而右移是算術(shù)右移拌消。
int div16(int x){
ins bias = (x>>31) & 0xF;
return (x+bias)>>4;
}