現代計算機存儲和處理信息以二值信號表示,這些二進制數字稱爲位。計算機用幾種不一樣的二進制表示來編碼數值。html
計算機將信息按位編碼,一般組織成字節序列。用不一樣的編碼方式表示整數、實數 和 字符串。前端
不一樣的計算機模型在編碼數字和多字節數據中的字節排序時使用不一樣的約定。git
c語言的設計能夠包容多種不一樣字長和數字編碼的實現。大多數機器對整數使用補碼編碼,而對浮點數使用IEEE
浮點編碼。程序員
在相同長度無符號和有符號整數之間進行強制類型轉換時,大多數C語言實現遵循的原理則是底層的位模式不變。編程
在補碼機器上,對於一個w位的值,這種行爲是由函數T2UW
和U2TW
來描述的安全
強制類型轉換來容許以種數據類型引用一個對象,而這種數據類型與建立這個對象時定義的數據類型不一樣。大多數編程不推薦這種編碼技巧,可是對系統級編譯程序是很是有用的,甚至是必須的,可是會出現許多程序員沒法預計的結果,經常致使程序錯誤函數
因爲編碼長度有限,與傳統整數和實數相比,計算機運算具備徹底不一樣的屬性。當超出表示範圍時,有限長度可以引發數值溢出。例如:當浮點數很是接近於0.0,從而轉換成0時,也會下溢出。學習
在移位運算中,注意區分邏輯右移和算數右移。邏輯右移在左端補k個零,算數右移在左端補k個最高位有效值。左移就是向左移動k位,丟棄最高的k位,並在右端補k個零優化
c語言實現的有限整數運算和真實的整數運算相比有一些特殊屬性。例如:因爲溢出,200300400*500會得出結果-884 901 888(使用32位來表示數據類型int),可是無符號數和補碼的運算都知足整數運算的結合律、交換律和分配律,能夠容許編譯器作不少的優化。編碼
浮點表示經過數字編碼爲x*2^y
的形式近似表示實數
注意由於浮點數只有有限的範圍和精度,不會遵照廣泛的算數屬性。
關於大端法和小端法
最開始在理解二者定義的時候都沒有問題,區分兩者的不一樣在於有效字節的排列高低。最低有效字節在最前面成爲小端法,最高有效字節在最前端稱爲大端法。
可是書上關於Ox01234567的例子爲何高位字節的十六進制是Ox01 低位十六進制是Ox67?
後來經過作課後習題關於Ox87654321的例子明白了,由於每一個十六進制的數字,在地址排列中有兩個通用規則。考慮一個w位的數,位表示爲[Xw-1,Xw-2,...,X1,X0]
其中Xw-1
是最高位,X0
是最低位.這樣一來就能夠明白高位字節是Ox01,低位字節是Ox67,這樣問題就順利解決了。
關於表示字符串
經過之前的學習也知道是由一張ASCII字符碼錶,可是對於使用使用ASCII做爲字符碼的任何系統上會獲得相同結果,與字節順序和字大小規則無關並不太理解。
在虛擬機下使用man ascii
獲得一張ASCII表,並用書上的例子
const cahr *s ="abcdef" show_bytes( (byte_pointer)s,strlen(s));
解決了這一問題。
關於掩碼運算
根據定義這裏掩碼是一個位模式,表示從一個字中選出的位的集合。根據計算x&OxFF
生成一個由x的最低有效字節組成的值,而其餘的字節就被置爲0。可是書上的例子X=Ox89ABCDEF和OxFF作&運算,爲何結果Ox000000EF,後來知道在運算的時候須要將它換算成二進制數才能進行運算,十六進制沒法直接進行運算。
關於有符號數和無符號數
建立按一個無符號常量,必須加上後綴字符「u」
或者「U」
。容許爲無符號數和有符號數之間的轉換,轉換的原則是底層位保持不變。在轉換時候能夠採用隱式,這樣就解決了書上p48的練習遇到的問題。
隱式相似於:
int x,y; unsigned ux, uy; x=ux; y=uy; 由於在代碼段中省略了`x=(int)ux ; `因此在編寫代碼的時候容易出錯,必定要區分清楚哪一個是符號數哪一個是無符號數。
書p28頁關於強制轉換
關於強制類型轉換,最開始在編譯代碼的時候遇到了問題。
加上一個主函數mian()
,就能夠解決。
可是要注意,定義輸入數字的時候須要定義成float格式,float能夠強制轉換成lnt格式,可是若是定義成int格式,若是定義成int格式再強制轉換成float格式會發生錯誤。
書p44頁關於有符號和無符號數之間相互轉換
C語言容許在各類不一樣的數字數據類型之間作強制類型轉換。
起初對於代碼段
short int v = -12345 unsigned short uv = (unsigned short) v; printf(「v = %d ,uv = %u\n」,v,uv);
理解起來存在一些問題,後來套用到一個主函數中,gcc編譯gdb設斷點理解就會容易許多。
書p47頁有符號數和無符號數和p49頁擴展一個數字的位表示
C語言支持全部整型數據類型的有符號和無符號的運算。
將一個無符號數轉換爲一個更大的數據類型,在表示的開頭添加0,稱爲零擴展。
將一個補碼數字轉換爲一個更大的數據類型能夠執行符號擴展。
將代碼段套在一個main主函數中,編譯運行一下就會容易理解許多。
代碼傳到開源中國代碼託管:https://git.oschina.net/20145335/Linux-besti-is-20145335.git
已經學了三週的《深刻理解計算機系統》,這周學到的知識,補碼,反碼等,包括溢出等知識點雖然之前在計算機導論和c語言基礎的課程上都有所瞭解,可是將這些知識點放在一個全新的Linux系統下理解就有不少的不同了,不論在理解方面仍是運用的方面都是新的知識。須要多加練習多多鞏固,雖然這周的知識都偏向於基本知識,可是編程的須要也是必不可少的,對於一些代碼段的理解仍是須要本身動手去實踐編譯和運行才能感悟更深。
代碼行數(新增/累積) | 博客量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 | |
第一週 | 180/200 | 2/2 | 18/20 | |
第二週 | 460/500 | 2/4 | 18/38 | |
第三週 | 650/1000 | 3/7 | 54/60 | 熟練使用gcc與gdb |