1. 程式人生 > >深入理解計算機系統_第一部分_第二章_資訊的表示和處理

深入理解計算機系統_第一部分_第二章_資訊的表示和處理

深入,並且廣泛
				-沉默犀牛

文章導讀

這一章介紹了計算機中資訊(即二值訊號)的表示和處理。

  1. 資訊儲存
    1.1 十六進位制表示法:介紹了十六進位制的產生和十六進位制、十進位制、二進位制之間的相互轉換規律
    1.2 字資料大小:介紹了在不同機器和編譯器中,資料型別資料在記憶體中所佔的大小
    1.3 定址和位元組順序 : 介紹了定址方法和位元組順序(小端法、大端法),float與int的二進位制表示有聯絡
    1.4 表示字串:介紹了字串的編碼方式,以ASCII為例,說明了文字資料比二進位制資料移植性好
    1.5 表示程式碼:介紹了在不同機器上產生的機器指令是不同的
    1.6 布林代數簡介:介紹了布林代數及四種運算(~、&、|、^)
    1.7 C語言中的位級運算:介紹了布林運算在C語言中的運用
    1.8 C語言中的邏輯運算:介紹了C語言中的邏輯運算及與位級運算的不同
    1.9 C語言中的移位運算:介紹了左移和右移(邏輯右移和算術右移)
  2. 整數表示
    2.1 整數資料型別:介紹了常見的整數資料型別
    2.2 無符號數的編碼
    2.3 補碼編碼
    2.4 有符號數和無符號數之間的轉換:同樣的位模式應用不同的解釋方法
    2.5 C語言中的有符號數與無符號數:著重提及了有符號數與無符號數混雜時的潛在危險
    2.6 擴充套件一個數字的位表示:介紹了無符號數的零擴充套件和補碼數的符號擴充套件
    2.7 截斷數字:介紹了無符號數的截斷和補碼數的截斷
  3. 整數運算
    3.1 無符號加法:介紹了無符號數加法和溢位
    3.2 補碼加法:介紹了補碼數的加法和溢位
    3.3 補碼的非 : 非是指加法逆元
    3.4 無符號乘法
    3.5 補碼乘法:簡單方法是轉換為10禁止計算後轉換為二進位制後截斷
    3.6 乘以常數:把常數轉為 2的任意次冪的相互加減
    3.7 除以2的冪:分為無符號和有符號(補碼)除法
    3.8 關於整數運算的最後思考:思考有限字長對於結果的影響
  4. 浮點數
    4.1 二進位制小數
    4.2 IEEE浮點表示:分為規格化、非規格化和特殊值
    4.3 數字示例
    4.4 舍入:分為向偶數舍入、向零舍入、向下舍入、向上舍入
    4.5 浮點運算:加法可交換不可結合,乘法不具有結合性,不具有加法分配性

資訊的表示和處理

現在計算機儲存和處理的資訊以二值訊號表示。對於有10個手指的人類來說,使用十進位制是很自然的事情,但是當構造儲存和處理資訊的機器是,二進位制工作得更好。二值訊號能夠很容易得被表示、儲存和傳輸,例如,可以表示為穿孔卡片上有洞或無洞、導線上的高電壓或低電壓,或者順時針或者逆時針的磁場。對二值訊號進行儲存和執行計算的電子電路非常簡單和可靠,製造商能夠在一個單獨的矽片上整合數百萬甚至數十億個這樣的電路。

[說不定這個宇宙中有一個星球,在那上面的生物長了3個手指,那他們一定就是3進位制的吧哈哈哈哈哈]

孤立地講,單個的位不是非常有用。然而,當把位組合在一起,再加上某種解釋,即賦予不同的可能位模式以含義,我們就能夠表示任何有限集合的元素。比如,使用一個二進位制數字系統,我們能夠用位組來編碼非負數。通過使用標準的字元碼,我們能夠對文件中的字母和符號進行編碼。

我們研究三種最重要的數字表示。無符號(unsigned)編碼基於傳統的二進位制表示法,表示大於或者等於零的數字。補碼(two‘s-complement)編碼是表示有符號整數的最常見的方式,有符號整數就是可以為正或者為負的數字。浮點數(floating-point)編碼是表示實數的科學計數法的以2為基數的版本。計算機用這些不同的表示方法實現算術運算,例如加法和乘法,類似於對應的整數和實數運算。

計算機的表示法是用有限數量的位來對一個數字編碼,因此,當結果太大以至於不能表示時,某些運算就會溢位(overflow)。溢位會導致某些令人吃驚的後果。例如,在今天的大多數計算機上(使用32位來表示資料型別int),計算表示式200300400*500會得出-884901888。這違背了整數運算的特性,計算一組正數的乘積不應產生一個負的結果。

另一方面,整數的計算機運算滿足人們所熟知的真正整數運算的許多特性。例如,利用乘法的結合律和交換律。雖然計算機可能沒有產生期望的結果(人類期望),但是至少它是一致的!

浮點運算有完全不同的數學屬性。雖然溢位會產生特殊的值正無窮,但是一組正數的乘積總是掙得。由於表示的精度有限,浮點運算是不可結合的。例如,在大多數機器上,C表示式(3.14 + 1e20)- 1e20求得的值會是0.0,而3.14 +(1e20 - 1e20)求得的值會是3.14。整數運算和浮點運算會有不同的數學屬性是因為它們處理數字表示有限的方式不同——整數的表示雖然只能編碼一個相對較小的數字範圍,但是這種表示是精確的;而浮點數雖然可以編碼較大的數值範圍,但是這種表示只是近似的。

通過研究數字的實際表示,我們能夠了解可以表示的值的範圍和不同算術運算的屬性。大量的計算機的安全漏洞都是由於計算機算術運算的微妙細節引發的。這導致了眾多的黑客企圖利用他們能找到的任何漏洞,不經過授權就進入他人的系統。

[學習微機的時候就覺得數字的儲存和運算很麻煩,終於還是逃不脫啊。。。]

2.1 資訊儲存

大多數計算機使用8位的塊,或者位元組(byte),作為最小的可定址的記憶體單位,而不是訪問記憶體中單獨的位[把8個位想成一個班級,校領導能找的最小單位是班級]。機器級程式將記憶體視為一個非常大的位元組陣列,稱為虛擬記憶體。記憶體的每個位元組都由一個唯一的數字來標識,稱為它的地址,所有可能地址的集合就稱為虛擬地址空間。顧名思義,這個虛擬地址空間只是一個展現給機器級程式的概念性映像。實際的實現是將動態隨機訪問儲存器、快閃記憶體、磁碟儲存器、特殊硬體和作業系統軟體結合起來,為程式提供一個看上去統一的位元組陣列。

在接下來的幾章中,我們將講述編譯器和執行時系統是如何將儲存空間劃分為更可管理的單元,來存放不同的程式物件(program object),即程式資料、指令和控制資訊。可以用各種機制來分配和管理程式不同部分的儲存。這種管理完全是在虛擬地址空間裡完成的。例如,C語言中一個指標的值(無論它指向一個整數、一個結構或是某個其他程式物件)都是某個儲存塊的第一個位元組的虛擬地址。C編譯器還把每個指標和型別資訊聯絡起來,這樣就可以根據指標值的型別,生成不同的機器級程式碼來訪問儲存在指標所指向位置處的值。儘管C編譯器維護著這個型別資訊,但是它生成的實際機器級程式並不包含關於資料型別的資訊。每個程式物件可以簡單地視為一個位元組塊,而程式本身就是一個位元組序列。

指標是C語言的一個重要特性。它提供了引用資料結構(包括陣列)的元素的機制。與變數類似,指標也有兩個方面:值和型別。它的值表示某個物件的位置,而它的型別表示那個位置上所儲存物件的型別(比如整數或者浮點數)。

2.1.1 十六進位制表示法

一個位元組由8位組成。在二進位制表示法中,它的值域是00000000 ~ 11111111。如果看成十進位制數,它的值域就是0 ~ 255。兩種符號表示法對於描述位模式來說都不是非常方便。二進位制表示法太冗長,而十進位制表示法與位模式的互相轉化很麻煩。替代的方法是,以16為基數,或者叫做十六進位制(hexadecimal)數,來表示位模式。十六進位制(簡寫hex)使用數字“0” ~ “9” 以及字元“A”~“F”來表示16個可能的值[馬路上的紅燈超時間超過100秒後就會用A ~ F來表示]。用十六進位制書寫,一個位元組的值域為00~FF。

在C語言中,以0x或0X開頭的數字常量被認為是十六進位制的值。字元A~F既可以是大寫,也可以是小寫,也可以是大小寫混合。

記住十六進位制與十進位制轉化的竅門就是,記住十六進位制A、C、F相應的十進位制數,這樣對於B、D、E的十進位制數只要加1即可。

比如,給你一個數字0x173A4C。可以通過展開每個十六進位制數字,將它轉換為二進位制格式,如下圖所示:
在這裡插入圖片描述

反過來,如果給你一個二進位制數,可以通過首先把它分為每4位一組來轉化為十六進位制。不過要注意,如果位總數不是4的倍數,最左邊的一組要前面補0,然後再將每個4位組轉換為相應的十六進位制數字:
在這裡插入圖片描述

[這個內容是比較簡單的,進位制轉換是程式設計師的基本功吧,不過才知道原來十六進位制的提出是為了簡便的。]

十進位制和十六進位制表示之間的轉換需要使用乘法或者除法來處理一般情況,例如,十進位制為314156,則如下圖:在這裡插入圖片描述

所以十六進位制表示為 0x4CB2C。
如果十六進位制為0x7AF,則十進位制數為7×16的平方 + 10×16 + 15 = 1967

2.1.2 字資料大小

每臺計算機都有一個字長(word size),指明指標資料的標稱大小(nominal size)。因為虛擬地址是以這樣的一個字來編碼的,所以字長決定的最重要的系統引數就是虛擬地址的最大大小。也就是說,對於一個字長為w位的機器而言,虛擬地址的範圍為0~(2的w地方 )- 1,程式最多訪問(2的w次方)個位元組。

[看來我們的系統分為32位64位的差別就在於此,所以同樣的機器既可以裝32位的系統,也可以裝64位的系統,因為這個位數決定了虛擬地址的大小,跟實際你的機器的實體記憶體大小沒關係。

但是大多數軟體就分為了32位版本64位版本,因為軟體就需要用到虛擬地址,32位64位的虛擬地址大小不同,所以如果裝錯了會出現藍屏等現象,我想一定是64位的軟體裝在了32位的系統上,請求了超過4GB(2的32次方)-1)這個大小的地址,就藍屏了。]

最近這些年,出現了大規模的從32位字長機器到64位字長機器的遷移。32位字長限制虛擬地址空間為4GB,擴充套件到64位字長使得虛擬地址空間為16EB。

大多數64位機器也可以執行(為32位機器編譯)的程式,這是一種後向相容。我們將程式稱為“32位程式”或者“64位程式”時,區別在於該程式是如何編譯的,而不是其執行的機器型別。

計算機和編譯器支援多種不同方式編碼的數字格式,如不同長度的整數和浮點數。比如,許多機器都有處理單個位元組的指令,也有處理表示為2位元組、4位元組或者8位元組整數的指令,還有些指令支援表示為4位元組和8位元組的浮點數。

C語言支援整數和浮點數的多種資料格式。有些資料型別的確切位元組數依賴於程式是如何被編譯。

在這裡插入圖片描述
為了避免由於依賴“典型”大小和不同編譯器設定帶來的奇怪行為,ISO C99引入了一類資料型別,其資料大小是固定的,不隨編譯器和機器設定而變化。其中就有資料型別int32_tint64_t,它們分別是4個位元組和8個位元組。使用確定大小的整數型別是程式設計師準確控制資料表示的最佳途徑。

[怪不得我在很多程式中看到int32_tint64_t這兩種定義方法,原來是為了固定資料大小。]

程式設計師應該力圖使它們的程式在不同的機器和編譯器上可移植。可移植性的一個方面就是使程式對不同資料型別確切大小不敏感。如果不關注這個問題,就有可能出現錯誤,比如,許多程式設計師假設一個宣告為int型別的程式物件能被用來儲存一個指標。這在大多數32位的機器上能正常工作,但是在一臺64位的機器上卻會導致問題。

[這一點我很疑惑,int型別在32位機器為4個位元組,作為指標的話最大地址為4GB,但是64位機器的定址地址最大為16EB,是大於4GB的,為啥會導致問題呢??????]

2.1.3 定址和位元組順序

對於跨越多位元組的程式物件,我們必須建立兩個規則:這個物件的地址是什麼,以及在記憶體中如何排列這些位元組。在幾乎所有的機器上,多位元組物件都被儲存為連續的位元組序列,物件的地址為所使用位元組中最小的地址。例如,假設一個型別為int的變數x的地址為0x100,也就是說,地址表示式&x的值為0x100。那麼(假設資料型別int為32位表示)x的4個位元組將被儲存在記憶體的0x100、0x101、0x102、0x103位置。

排列表示一個物件的位元組有兩個通用的規則。即小端法(little endian)大端法(big endian)小端法是指機器選擇在記憶體中按照從最低有效位元組到最高有效位元組的順序儲存物件;大端法是指機器選擇在記憶體中按照從最高有效位元組到最低有效位元組的順去儲存物件。

假設變數x的型別為int,位於地址0x100處,它的十六進位制值為0x01234567。
在這裡插入圖片描述

注意,在字0x01234567中,高位位元組的十六進位制值是0x01,而地位位元組是0x67。在哪種位元組順序是合適的這個問題上,人們表現得非常情緒化。但其實只要選擇了一種規則並且始終如一地堅持,對哪種位元組排序的選擇都是任意的。

對於大多數應用程式設計師來說,其機器所使用的位元組順序是完全不可見的。無論為哪種型別的機器所編譯的程式都會得到同樣的結果。不過有的時候,位元組順序會成為問題。

  1. 在不同型別的機器之間通過網路傳送二進位制資料時,小端法機器產生的資料傳送到大端法機器時(或者反過來),字裡的位元組成了反序的。為了避免這類問題,網路應用程式的程式碼必須遵守已經建立的關於位元組順序的規則,以確保傳送方機器將它內部表示轉換成網路標準,而接收方機器則將網路標準轉換為它的內部表示。
  2. 閱讀表示整數資料的位元組序列時位元組順序也很重要。這通常發生在檢查機器級程式時。就是在小端法機器生成的機器級程式表示中,書寫位元組序列的方式是最低位位元組在左邊,最高位在右邊,這正好與通常人類書寫數字時最高有效位在左邊,最低有效位在右邊的方式相反。
  3. 編寫規避正常的型別系統的程式時位元組順序也會很重要,在C語言中,可以通過使用強制轉換型別(cast)聯合(union)來允許以一種資料型別引用一個物件,而這種資料型別與建立這個物件時定義的資料型別不同。

這裡展示一段C程式碼,及其測試程式和結果:
在這裡插入圖片描述
在這裡插入圖片描述

在這裡插入圖片描述

引數12345的十六進位制表示為0x00003039。

  1. 對於int型別的資料,除了位元組順序以外,我們在所有機器上得到了相同的結果。(我們可以看到在Linux 32、windows和Linux 64上,最低有效位元組0x39最先輸出,這說明它們是小端法機器;而在Sun上最後輸出,這說明Sun是大端法機器。)
  2. float資料的位元組,除了位元組順序以外,也都是相同的。
  3. 指標值卻是完全不同的。不同的機器/OS配置使用不同的儲存分配規則,Linux 32、Windows和Sun的機器使用4位元組地址,而Linux 64使用8位元組地址。

可以觀察到,儘管float和int資料都是對數值12345編碼,但是它們有截然不同的位元組模型:int為0x00003039,而float為0x4640E400。如果我們將這些十六進位制模式擴充套件為二進位制形式,並且適當地將它們移位,就會發現一個有13個相匹配的位的序列:
在這裡插入圖片描述

這不是巧合,以後研究浮點數格式的時候,還將再回到這個例子。

2.1.4 表示字串

C語言中字串被編碼為一個以null字元結尾的字元資料。每個字元都由某個標準編碼來表示,最常見的是ASCII字元碼。因此,如果我們以引數“12345”和6來執行上面的show_bytes,我們得到結果31 32 33 34 35 00。注意,十進位制數字x的ASCII碼正好是0x3x,而終止位元組的十六進位制表示為0x00。在使用ASCII碼作為字元碼的任何系統上都將得到相同的結果,與位元組順序和字大小規則無關。因而,文字資料比二進位制資料具有更強的平臺獨立性。

2.1.5 表示程式碼

考慮下面的C函式:
在這裡插入圖片描述

當我們在示例機器上編譯時,生成如下位元組表示的機器程式碼:
在這裡插入圖片描述

我們發現指令編碼是不同的。不同的機器型別使用不同的且不相容的指令和編碼方式。即使是完全一樣的程序,執行在不同的作業系統上也會有不同的編碼規則,因此二進位制程式碼是不相容的。二進位制程式碼很少能在不同機器和作業系統組合之間移植。

計算機系統的一個基本概念就是,從機器的角度來看,程式僅僅只是位元組序列。機器沒有關於原始源程式的任何資訊,除了可能用來幫助除錯的輔助表以外。

[怪不得在轉移程式碼的時候,是轉移.c檔案到對方電腦上去編譯,而不是直接轉移.o檔案,原來是我自己電腦上的.o檔案到對方電腦不能用的。]

2.1.6 布林代數簡介

二進位制值是計算機編碼、儲存和操作資訊的核心,所以圍繞數值0和1的研究已經演化出了豐富的數學知識體系。
在這裡插入圖片描述
最後圖表中的^代表了異或。

將上述4個布林運算擴充套件到位向量的運算,位向量就是固定長度為w、由0和1組成的串。假設a = [0110] ,b = [1100],則四中運算:
在這裡插入圖片描述

布林運算的運演算法則有符合分配律:
&對|的分配律 :a & ( b | c ) = ( a & b ) | ( a & c )
|對&的分配律 :a | ( b & c ) = ( a | b ) & ( a | c )

此外布林運算還有一個有趣的屬性:
a ^ a = 0
0 ^ 0 = 1 ^ 1 = 0
( a ^ b ) ^ a = b

即a是a的加法逆元

位向量一個很有用的應用就是表示有限集合。比如,a = [ 011010001 ]表示集合A = { 0 , 3 , 5 , 6 },而 b = [ 01010101 ]表示集合B = { 0 , 2 , 4 , 6 }。

在大量實際應用中,我們都能看到用位向量來對集合編碼。例如,我們會看到很多不同的訊號會中斷程式執行。我們能夠通過指定一個位向量掩碼,有選擇地使能或遮蔽一些訊號,其中某一位位置上為1時,表示訊號i是有效的,而0表明該訊號是被遮蔽的。因此,這個掩碼錶示的就是設定為有效訊號的集合。

2.1.7 C語言中的位級運算

C語言的一個很有用的特性就是它支援按位布林運算。以上的四種布林運算(| 、 & 、 ~、 ^ )可以運用到任何“整形”的資料型別上。下圖是對char資料型別表示式求值的例子:
在這裡插入圖片描述

確定一個位級表示式的結果最好的方法,就是將十六進位制的引數擴充套件成二進位制表示並執行二進位制運算,然後再轉換回十六進位制。

上面說過位級運算的一個常見用法就是實現掩碼運算,這裡的掩碼是一個位模式,表示從一個字中選出的位的集合。舉個例子,掩碼0xFF(最低的8位為1)表示一個字的低位位元組。位級運算( x & 0xFF )生成一個由 x 的最低有效位元組組成的值,而其他的位元組就被置為0。比如, x = 0x89ABCDEF,其表示式將得到0x000000EF。

2.1.8 C語言中的邏輯運算

C語言還提供了一組邏輯運算子|| 、 &&、 !,分別對應於命題邏輯中的OR、AND和NOT運算。邏輯運算很容易和位級運算相混淆,但是它們的功能是完全不同的。邏輯運算認為所有非零的引數都表示TRUE,而引數0表示FALSE。
在這裡插入圖片描述

看得出來,按位運算只有在特殊情況下,也就是引數被限制為0或者1時,才和與其對應的邏輯運算有相同的行為。

2.1.9 C語言中的移位運算

C語言還提供了移位運算,向左或者向右移動位模式。

左移運算:x << k ,向左移動 k 位,丟棄最高的 k 位,並在右端補 k 個0。
右移運算:x >> k ,向右移動 k 位,但是它的行為有點微妙。一般而言,機器支援兩種形式的右移邏輯右移算術右移邏輯右移在左邊補 k 個0,算術右移是在左端補 k 個最高有效位的值(雖然看上起很奇特,但是它對有符號整數資料的運算非常有用)。
以下是例子:
在這裡插入圖片描述

C語言標準並沒有明確定義對於有符號數應該使用哪類右移——算術右移邏輯右移都可以。不幸地,這就意味著任何假設一種或者另一種右移形式的程式碼都可能遇到可移植性的問題。然而實際上,幾乎所有的編譯器/機器組合都對有符號數使用算術右移,且許多程式設計師也都假設機器會使用算術右移。對於無符號數,右移必須是邏輯右移

還需要注意的就是,必須要保證位移量 k 小於待移位值的位數。

2.2 整數表示

在本節中,我們描述用位來編碼整數的兩種不同的方式:一種只能表示非負數,而另一種能夠表示負數、零和整數。
下表展示引入一些數學術語,這些術語會在描述的過程中介紹。

在這裡插入圖片描述

2.2.1 整型資料型別

C語言支援多種整型資料型別——表示有限範圍的整數。這裡給出來的唯一一個與機器相關的取值範圍是大小指示符long的。大多數64位機器使用8個位元組的表示,比32位機器使用的4個位元組的表示的取值範圍大很多。
在這裡插入圖片描述
在這裡插入圖片描述

以上兩個圖示有一個值得注意的特點:取值範圍不對稱——負數的範圍比整數的範圍大 1 。

C語言標準定義了每種資料型別必須能夠表示的最小的取值範圍。如下圖,它們的取值範圍與上面所示的典型實現一樣或者小一些。特別的,除了固定大小的資料型別是例外,我們看到它們只要求正數和負數的取值範圍是對稱的。此外,資料型別int可以用兩個位元組的數字來實現,這幾乎回退到了16位機器的時代。long的大小可以用4個位元組的數字來實現。
在這裡插入圖片描述

2.2.2 無符號的編碼

無符號數即位向量的每一個位都成為數字值的一部分,我們用一個函式B2U(Binary to Unsigned)來表示:
在這裡插入圖片描述

下面示例幾種情況下的B2U給出的從位向量到整數的對映:
在這裡插入圖片描述

無符號數的二進位制表示有一個很重要的屬性,就是每個介於0 ~ (2的w次方 )- 1 的數都有唯一一個w位的值編碼,比如十進位制數11作為無符號數,只有一個4為表示,即[ 1011 ]。
在這裡插入圖片描述

數學術語雙設是指一個函式 f 有兩面:它將數值 x 對映為數值 y ,即 y = f ( x ) ,但是它也可以反向操作,即 x = f-1 ( y )。

2.2.3 補碼編碼

許多情況下,我們還希望表示負數值。最常見的有符號數的計算機表示方式就是補碼(two's-complement)形式。這個定義中,將字的最高有效位解釋為負權(negative Weight)。我們用函式B2T(Binary to Two’s - complement)來表示。
在這裡插入圖片描述

最高有效位也成為符號位,它的權重-(2的w-1次方),是無符號表示中權重的負數。符號位被設定為 1 時,表示值為負,反之為非負。在這裡插入圖片描述

B2T也是一個雙射函式
在這裡插入圖片描述

在這裡插入圖片描述

關於這些數字,有幾個點值得注意:

  1. 補碼範圍是不對稱的,Tmin絕對值 = Tmax絕對值 + 1,也就是說 Tmin沒有與之對應的正數。之所以有這樣的不對稱性,是因為一半的位模式(符號位 = 1)表示負數,而另一半(符號位 = 0)表示非負數。因為0是非負數,也就以為著能表示的正數比負數少一個。
  2. 最大的無符號數值剛好比補碼的最大值的兩倍大一點,Umax = 2 * Tmax + 1。補碼錶示中所有表示負數的位模式在無符號表示中都變成了正數。
  3. 注意 -1 和 Umax 有同樣的位表示——一個全1的串
  4. 數值 0 在兩種表示方式中都是全0的串

C語言標準並沒有要求用補碼形式來表示有符號整數,但是幾乎所有的機器都是這麼做的。所以如果我們希望程式碼有最大可移植性,除了C語言標準定義的資料型別的數值範圍之外,不能再假設任何可表示的數值範圍,也不能假設有符號數會使用何種特殊的表示方式。

為了更好地理解補碼,考慮下面的程式碼:
在這裡插入圖片描述

當在大端法機器上執行時,這段程式碼的輸出為 30 39 cf c7,指明 x 的十六進位制表示為0x3039,mx 的十六進位制表示為0xcfc7,分別展開為位模式,x = [ 0011 0000 0011 1001] ,mx = [ 1100 1111 1100 0111 ],對這兩個位模式生成的值為 12345 和 -12345。
在這裡插入圖片描述

2.2.4 有符號數和無符號數之間的轉換

C語言允許在不同的數字資料型別之間做強制型別轉換。例如,假設變數 x 宣告為 int,u 宣告為 unsigned。表示式(unsigned)x 會將 x 的值轉化為一個無符號數值,而(int)u 將 u 的值轉換為一個有符號整數。
那麼強制型別轉換會得到什麼結果呢?對於大多數C語言的實現來說,對於這個問題的回答是從位級角度來看的,而不是數的角度,即轉換前後的二進位制位模式不會變,只是解釋方式改變了。

比如如下的程式碼:
在這裡插入圖片描述
在一臺採用補碼的機器上,上述程式碼會產生如下輸出:
v = -12345, uv = 53191
在上面的表格中看到了,-12345 的16為補碼 和 53191的無符號表示的位模式是一樣的。

第二個例子:
在這裡插入圖片描述
在一臺採用補碼的機器上,上述程式碼會產生如下輸出:
u = 4294967295, tu = -1

對於32位字長來說,無符號形式的4294967295(Umax)和補碼形式的 -1 的位模式是完全一樣的。將unsigned強制型別轉換為 int ,底層的位表示保持不變。

從這個例子來看,T2U(- 12345 ) = 53191,U2T( 53191 ) = -12345。也就是說,十六進位制表示寫作 0xCFC7 的16位位模式既是 -12345 的補碼錶示,優勢 53191 的無符號表示。同時,12345 + 53191 = 65535 = 2的16次方。這個屬性可以推廣到給定位模式的兩個數值(補碼和無符號數)之間的關係。類似的,T2U(-1) = 4294967295,冰鞋U2T(4294967295) = -1。同時,1 + 4294967295 = 4294967296 = 2的32次方。

也就是說,無符號表示中的Umax有著和補碼錶示的 -1 相同的位模式。這兩個數的關係: 1 + Umax = 2的w次方。

在這裡插入圖片描述
[這些答案都是我親自算過的,有不懂的可以直接留言問我。]

2.2.5 C語言中的有符號數與無符號數

C語言勻速無符號數和有符號數之間的轉換,大多數系統遵循的原則是底層的位表示保持不變。

顯示的強制型別轉換就會導致轉換髮生:
在這裡插入圖片描述

另外,當一種型別的表示式被賦值給另外一種型別的變數時,轉換是隱式發生的:
在這裡插入圖片描述

當用printf輸出數值時,分別用 %d、 %u、 %x以有符號十進位制、無符號十進位制和十六進位制格式輸出一個數字。考慮下面的程式碼:

在這裡插入圖片描述

當在一個32位機器上執行時,它的輸出如下:
x = 4294967295 = -1
u = 2147483648 = -2147483648

當執行一個運算時,如果它的一個運算數是有符號的,另一個是無符號的,那麼C語言會隱式地將有符號數強制型別轉換為無符號數,並假設這兩個數都是非負的,來執行這個運算。

這對於像 < 和 > 這樣的關係運算符來說,它會導致非直觀的結果。
在這裡插入圖片描述

這裡假設資料型別 int 表示為32位補碼。考慮比較式 -1 < 0u。因為第二個運算數是無符號的,第一個運算數就會被隱式的轉換為無符號數,因此表示式就變為了 4294967295u < 0u,這個答案顯然為 0 。

在這裡插入圖片描述
[這些答案都是我親自算過的,有不懂的可以直接留言問我。]

2.2.6 擴充套件一個數字的位表示

一個常見的運算實在不同字長的整數之間轉換,同時又保持數值不變。當然,當目標資料型別太小以至於不能表示想要的值時,這根本就是不可能的。然而,從一個較小的資料型別轉換到一個較大的型別,應該總是可能的。

要將一個無符號數轉換為一個更大的資料型別,我們只要簡單地在表示的開頭新增0。這種運算被稱為零擴充套件(zero extension)

要將一個補碼數字轉換為一個更大的資料型別,可以執行一個符號擴充套件(sign extension),在表示中新增最高有效位的值。

考慮下面的程式碼:
在這裡插入圖片描述

在採用補碼錶示的32位大端法機器上執行這段程式碼時,列印如下:
在這裡插入圖片描述

可以看到,儘管-12345 的補碼錶示和 53191 的無符號表示在16位字長時是相同的,但是在32位字長時卻是不同的。特別地,-12345 的十六進位制表示為 0xFFFFCFC7,而 53191 的十六進位制表示為 0x0000CFC7。前者使用的是符號擴充套件——最開頭加了16位,都是最高有效位 1,表示為十六進位制就是0xFFFF。後者開頭使用16個0來擴充套件,表示為十六進位制就是0x0000。

練習題:
在這裡插入圖片描述
[可以看到這個練習中,從 [ 1011 ] 擴充套件到 [ 11011 ] 再擴充套件到 [ 111011 ] ,它們都是 -5 的補碼錶示。可見有符號數位擴充套件時候,左邊擴充套件符號位,不會對它的數值有影響。這些答案都是我親自算過的,有不懂的可以直接留言問我。]

在這裡插入圖片描述
在這裡插入圖片描述
[這些答案都是我親自算過的,有不懂的可以直接留言問我。]

2.2.7 截斷數字

假設我們不用額外的位來擴充套件一個數值,而是減少一個數字的位數。例如下面的情況:
在這裡插入圖片描述
當我們把 x 強制型別轉換為 short 時,我們就將32位的int截斷為了16位的short int。這個16位的位模式就是 -12345 的補碼錶示。當我們把它強制型別轉換回int時,符號擴充套件把高16位設定為 1,從而生成 -12345 的32位補碼錶示。

截斷一個數字可能會改變它的值——溢位的一種形式。對於一個無符號數,我們可以很容易得出其數值結果。

1.截斷無符號數
在這裡插入圖片描述
mod 是求模數的運算(求餘數),舉個例子:
B2U ( [ 10101 ] ) = 21
B2U ( [ 101 ] ) = 5
21 mod 8(2的3次方) = 5

B2U ( [ 11100 ] ) = 28
B2U ( [ 00 ] ) = 0
28 mod 4(2的2次方) = 0

  1. 截斷補碼數值(將最高位轉換為符號位):
    在這裡插入圖片描述

[這個我沒弄懂。。。之後弄明白了來更新]

在這裡插入圖片描述

[自己程式設計一定不會在變數賦值的時候造成截斷,給自己找麻煩。]

2.2.8 關於有符號數與無符號數的建議

像上一節看到的那樣,有符號數到無符號數的隱式強制型別轉換導致了某些非直觀的行為。而這些非直觀的特性經常導致程式錯誤,並且這種包含隱式強制型別轉換的細微差別的錯誤很難被發現。

用以下兩個例子來展現這種細微的錯誤:
在這裡插入圖片描述
在這裡插入圖片描述

[這裡可能有的疑問是 無符號0 - 1 = Umax,[0000] - [0001] = [1111] = Umax,所以這個條件就成了必然滿足的條件了。]

在這裡插入圖片描述

A: 當 s 比 t 短的時候,該函式會返回1
B:由於 strlen 被定義為產生一個無符號的結果,差和比較都採用無符號運算來計算。當 s 比 t 短的時候,strlen(s) - strlen(t)的差會為負,但是變成了一個很大的無符號數,大於0。
C:改為 return strlen(s) > strlen(t);

[ 舉個負數變成了很大的無符號數的例子: 3 - 4 ===> [0011] - [0100] = [1111] ,這個[1111] 視為有符號數(補碼),則為-1,結果正確了;視為無符號數,則為15,結果就錯了。]

我看到了很多無符號數運算的細微特性,尤其是有符號數到無符號數的隱式轉換,會導致錯誤或者漏洞的方式。避免這類錯誤的一種方法就是絕不使用無符號數。

當我們想要把字僅僅看作是位的集合而沒有任何數字意義時,無符號數值是非常有用的。例如,往一個字中放入描述各種布林條件的標記(flag)時,就是這樣。地址自然地就是無符號的,所以系統程式設計師發現無符號型別是很有幫助的。當實現模運算和多精度運算的數學包時,數字是由字的陣列來表示的,無符號值也會非常有用。

2.3 整數運算

剛入門的程式設計師非常驚奇地發現,兩個正數相加會得出一個負數,而比較表示式 x < y 和比較表示式 x - y < 0會產生不同的結果。這些屬性是由於計算機執行的有限性造成的。理解計算機運算的細微之處能夠幫助程式設計師編寫更可靠的程式碼。

2.3.1 無符號加法

如果兩個加數取值範圍是0-15(四位),但是和的取值範圍為0-30(五位),這樣的情況成為位元組膨脹,這意味著,想要完整的表示算術運算的結果,我們不能對字長做任何限制。但是常見的程式語言支援固定精度的運算,因此像“加法”和“乘法”這樣的運算不同於它們在整數上的相應運算。

x = 9 和 y = 12 的位表示分別是 [1001] 和 [1100] ,它們的和是21, 5位表示為 [10101] ,但是如果丟棄了最高位,我們得到了 [0101],是十進位制的5。這就和值 21 mod 16 = 5一致。

說一個算術運算溢位,是指完整的整數結果不能放到資料型別的位元組限制中去。下圖中,當 x + y < 16 時,沒有溢位,對應與圖中標記為“正常”的斜面。當 x + y >= 16 時,加法溢位,對應與圖中標記為“溢位”的斜面。

在這裡插入圖片描述

當執行C程式時,不會將溢位作為錯誤而發訊號,不過有時候,我們可能希望判定是否發生了溢位。
在這裡插入圖片描述
9 + 12 = 5 。 由於 5 < 9 ,我們可以看出發生了溢位。

在這裡插入圖片描述

練習題:
在這裡插入圖片描述

[ 十六進位制D的位模式為 [1101] 所以十進位制就是13,是無符號數,所以求反就是用(2的w次方 - x),16 - 13 = 3 ]

2.3.2 補碼加法

在這裡插入圖片描述

在這裡插入圖片描述

下圖描述了字長為4的補碼加法。運算數的範圍為-8 ~ 7之間。當 x + y < -8時,補碼加法就會負溢位,導致和增加了16。當 -8 <= x + y <= 8時,補碼加法就是x + y。當 x + y >= 8時,補碼加法就會正溢位,導致和減少了16。
在這裡插入圖片描述

溢位檢查:

在這裡插入圖片描述

練習題:
在這裡插入圖片描述

在這裡插入圖片描述
補碼相加會形成阿貝爾群,因此表示式(x + y)- x 總是得到y,無論加法是否溢位,而(x + y)- y 總是會得到x。

[模數相加會形成阿貝爾群 ,它是可交換的和可結合的。
模數加法即對任何兩個資料相加求模的運算,如任何對10的模數加法,如9 + 9 = 8。
補碼相加就是對2的w次方的模數相加,如 9 + 12 = 5,所以補碼相加模數相加,即一定形成阿貝爾群,即一定可交換可結合。 ]

2.3.3 補碼的非

在這裡插入圖片描述

這裡最好把無符號的非 和補碼的非 對比起來看:
無符號的非:
在這裡插入圖片描述

[無符號數的取反在上面說過了,這裡不再贅述]

補碼的非:
在這裡插入圖片描述

[因為是補碼,所以從十六進位制轉換為十進位制時要把位模式理解為補碼,D的位模式是 [1101] 要注意這是補碼,所以轉為十進位制的時候,-8 * 1 + 4 * 1 + 2 * 0 + 1 * 1 = -3 ,補碼數取非遵循上面的公式,-3 取非為 3,-5 取非為 5 ,-8(Tmin)取非為 -8 ]

補碼非的位級表示:
計算一個位級表示的值的補碼非有幾種聰明的方法。這些計數很有用(例如當你在除錯程式的時候遇到值0xfffffffa),同時它們也能夠讓你更多瞭解補碼錶示的本質。

執行位級補碼非的第一種方法是對每一位取反,再對結果加1。在C語言中,對於任意整數值x,計算表示式-x 和 ~x+1得到的結果完全相同。

示例如下:
在這裡插入圖片描述

[要注意這裡說的結果完全相同,是說轉化為十進位制的結果相同,不是位模式相同。-4的位模式是[1100] 取反後為 [0011] 加1後為 [0100] 轉換為十進位制為 4 ]

[之前總不明白原碼反碼補碼,以為有的編碼就是原碼,有的編碼就是補碼,現在才知道,編碼(即位模式)就是編碼,如果你把它當做了原碼,那讀出來的十進位制數就是無符號數,如果把它當做補碼,那讀出來的十進位制數就是有符號數。

比如位模式[1101],作為原碼,則讀出8 + 4 + 1 = 13,作為補碼,則讀出 -8 + 4 + 1 = -3。
]

2.3.4 無符號乘法

在這裡插入圖片描述

x 和 y 都是w位的無符號數,不管x * y 的結果需要用多少位來表示,C語言都將結果截斷為w位。而將一個無符號數截斷為w位等價於計算該值對(2的w次方)的模。

2.3.5 補碼乘法

在這裡插入圖片描述

補碼數(即有符號數)的乘積最後還是補碼數,對這個補碼數截斷為w位相當於計算該值對2的w次方求模,再把結果轉換為補碼。
[比如下圖中的 -3 * 3 = -9 ,-9 mod 8 = -1 ,-1 的補碼錶示就是[111]。]
在這裡插入圖片描述

小練習:
在這裡插入圖片描述

[這裡有幾道題有些難,我弄明白了來更新]
在之前XDR庫的程式碼的安全漏洞,就是因為乘法溢位導致的,如果在32位的機器上,兩個乘數結果的位模式超過了32位,截斷為32位以後就出問題了。

2.3.6 乘以常數

以往,在大多數機器上,整數乘法指令相當慢,需要10個或者更多的時鐘週期,然而其他整數運算(加法、減法、位級計算額移位)只需要1個時鐘週期。即使在Intel Core i7上,其整數乘法也需要3個時鐘週期。因此,編譯器使用了一項重要的優化,試著用移位和加法運算的組合來代替乘以常數因子的乘法。

首先考慮乘以2的冪的情況:

在這裡插入圖片描述

比如,4位。11的位模式為[1011]。k = 2時將其左移得到6位位模式[101100],即可編碼為無符號數11 * 4 = 44。

[左移一個數值等價於執行一個與2的冪相乘的無符號乘法。而且無論是無符號運算還是補碼運算,乘以2的冪都可能導致溢位。即使溢位的時候,我們通過移位得到的結果也是一樣的。]

由於整數乘法比移位和加法的代價大得多,許多C語言編譯器試圖以移位、加法和減法的組合來消除很多整數乘以常數的情況。比如,x * 14 = x * (8 + 4 + 2) = ( x << 3 ) + ( x << 2 ) + ( x << 1 ),將乘法替換為三個位移和兩個加法

[到這裡我有個疑問,x * 14 是可以這樣,那x * -14呢?其實,x * -14 = ( x << 1 ) - ( x << 4 )]

歸納一下:對於某個常數K的表示式 x * K 生成程式碼。編譯器會將K的二進位制表示為一組0和1交替的序列,比如14可以寫為[(0…0)(111)(0)]。考慮一組從位置n到位置m的連續的1(n >= m),(對於14來說 n = 3, m = 1。)我們可以用下面兩種方法來計算這些位對乘積的影響:
在這裡插入圖片描述

那麼怎麼選擇A還是B呢?原則是 n = m,選擇A;否則選擇B。其實就是為了儘可能的減少移位和加減的次數。

小練習:
在這裡插入圖片描述

2.3.7 除以2的冪

在大多數機器上,整數除法比整數乘法更慢——需要30個或者更多的時鐘週期。所以除以2的冪也是用移位來實現,只不過用的是右移。無符號和補碼分別使用邏輯右移和算術右移來實現

[還記得之前說過的嗎?左移只有一種,右移就分為了邏輯右移和算術右移,在這裡就用到了,邏輯右移是左邊補0,算術右移左邊補符號位]

在這裡插入圖片描述

直接以下面的例子來看,很直觀:
在這裡插入圖片描述

左端移入的0以斜體表示。並且移位總是舍入到零(例如771.25 舍入到 771)

在這裡插入圖片描述

對於x >= 0 ,變數x的符號位為0,所以效果和邏輯右移是一樣的。對於負數,會按照向下舍入(例如-771.25 會舍入到 -772)

看這個例子很直觀:
在這裡插入圖片描述

我們可以通過在移位之前偏置(biasing)這個值,來修正這個不合適的舍入
[為啥這是不合適的。。。我沒覺得不合適啊。。。]

在這裡插入圖片描述

看下面的例子:
在這裡插入圖片描述

現在我們可以看到,除以2的冪可以通過邏輯或者算術右移來實現。這也正是為什麼大多數機器上提供這兩種型別的右移。不過,這種方法不能想乘法那樣推廣到任意常數。

[是啊,乘以3 可以用(乘以4 - 本身)來實現,但是除以3 顯然沒辦法做出類似的操作。]

2.3.8 關於整數運算的最後思考

計算機執行的“整數”運算實際上是一種模運算形式。
表示數字的有限字長限制了可能的值的取值範圍,運算結果可能溢位。

補碼錶示提供了一種既能表示負數也能表示正數的靈活方法,同時使用了執行無符號算數相同的位級實現,包括加法、減法、乘法和除法,無論運算數是以無符號形式還是補碼形式表示的,都有完全一樣或者非常類似的位級行為。

我們看到了C語言中的某些規定可能會產生意想不到的結果,而這些結果可能是難以察覺或理解的缺陷的源頭。特別看到了unsigned資料型別,雖然它概念上很簡單,但可能導致意想不到的行為。這種資料型別還會以出乎意料的方式出現,比如書寫整數常數和呼叫庫函式時。
下面這道題很好,一起來做一下:
在這裡插入圖片描述

在這裡插入圖片描述

2.4 浮點數

浮點數對執行涉及非常大的數字、非常接近於0的數字,以及更普遍地作為實數運算的近似值的計算,是很有用的。

直到20世紀80年代,每個計算機制造商都設計了自己的表示浮點數的規則,以及對浮點數執行運算的細節。另外,它們常常不會太多地關注運算的精確性,而把實現的速度和簡便性看得比數字精確性更重要。
現在所有的計算機都支援IEEE浮點的標準,這大大提高了科學應用程式在不同機器上的可移植性。

本節中,我們將看到IEEE浮點格式中數字是如何表示的。我們還會探討舍入(rounding)的問題,即當一個數字不能被準確地表示為這種格式時,就必須向上或者向下調招。然後,我們將探討加法、乘法和關係運算符的數學屬性。許多程式設計師認為浮點數沒意思,往壞了說,深奧難懂。我們將看到,因為IEEE格式是定義在一組小而一致的原則上的,所以它實際上是相當優雅和容易理解的。

2.4.1 二進位制小數

理解浮點數的第一步是考慮含有小數值的二進位制數字。首先,讓我們來看看更熟悉的十進位制表示法。
在這裡插入圖片描述

數字權的定義與十進位制小數點符號(‘.’)相關,這意味著小數點左邊的數字的權是10的正冪,得到整數值,而小數點右邊的數字的權是10的負冪,得到小數值。例如
在這裡插入圖片描述

相關推薦

深入理解計算機系統》(第三版)第二部分知識點總結

資訊的表示和處理      本渣渣要進行CSAPP期中考了,但是上半學期啥也沒聽QWQ,只能臨陣磨槍了*學習要點*1、計算機如何表示數字2、其他形式資料的基本屬性*資訊儲存*位元組:最小的可定址的記憶體單位地址:記憶體中每個位元組都由一個唯一的數字來標識虛擬地址空間:所有可能

深入理解計算機系統第一學習筆記

文件 傳遞 ati 線性 邏輯 double 動態 內容 起源 信息就是位+上下文 源程序:就是一個由0和1組合的位(bit)序列,8位組成一字(byte),每個字節表示某個文本字符。 系統中所有的信息——包括磁盤文件、存儲器中的程序、存儲器中存放的用戶數據以及網絡上傳送的

2018-2019-1 20189206 《深入理解計算機系統第一學習筆記

2018-2019-1 20189206 《深入理解計算機系統》第一週學習總結 教材學習內容總結 第一章 計算機系統漫遊 讀後感 第一章給我的感覺就是將一個大概而具體的過程展現給我們,同時,每個步驟的更加具體的細節部分也是之後每一章的內容。一方面講解了計算機系統的構成、檔案在計算機中的儲存等問題。通過

深入理解計算機系統》讀書筆記——第七 連結

 連結 有兩個c檔案: /* main.c */ void swap(); int buf[2] = {1, 2}; int main() { swap(); return 0; } /* swap.c */ extern int buf[]; int *b

深入理解計算機系統 第三版 第三 家庭作業 答案

3.58long decode2(long x,long y,long z) { int ret; y=y-z; x=x*y; ret=y; ret<<=63; ret>>=63; return ret^x; }算術左移63再右移6

深入理解計算機系統》讀書筆記 —— 第三 程式的機器級表示

>本章主要介紹了計算機中的機器程式碼——組合語言。當我們使用高階語言(C、Java等)程式設計時,程式碼會遮蔽機器級的細節,我們無法瞭解到機器級的程式碼實現。既然有了高階語言,我們為什麼還需要學習組合語言呢?學習程式的機器級實現,可以幫助我們理解編譯器的優化能力,可以讓我們瞭解程式是如何執行的,哪些部分是可以

深入理解計算機系統_第一部分_第三_程式的機器級表示

深入,並且廣泛 -沉默犀牛 文章導讀 計算機執行機器程式碼,用位元組序列編碼低階的操作,包括處理資料、管理記憶體、讀寫儲存裝置上的資料,以及利用網路通訊。編譯器基於程式語言的規則、目標機器的指令集和作業系統遵循的慣例,經過一系列的階段生成機器程式碼。GCC C語言編譯器以彙

深入理解計算機系統_第一部分_第二_資訊表示處理

深入,並且廣泛 -沉默犀牛 文章導讀 這一章介紹了計算機中資訊(即二值訊號)的表示和處理。 資訊儲存 1.1 十六進位制表示法:介紹了十六進位制的產生和十六進位制、十進位制、二進位制之間的相互轉換規律 1.2 字資料大小:介紹了在不同機器和編譯器中,資料型別資料

深入理解計算機系統_第零部分_第一_計算機系統漫遊

深入,並且廣泛 -沉默犀牛 寫在前面 今天是2018/12/14,還有一週我的實習期就結束了,發現自己的基礎特別薄弱,選了幾本提升基礎的書籍,《深入理解計算機系統》是我將要看的第一本書,特別開這個系列文章,記錄所學所得所想,也用作檢驗自己學習進度的指標之一。 PS:大部分是

讀書筆記——《深入理解計算機系統》第三_程式的機器級表示(一)

    前言:已經大四,沒有去找工作,選擇了保研,之所以這樣選擇,有三個原因,一、剛進校時,聽說保研都是牛人才能行的事,所以一心努力保研;二、2008年開始,經濟危機比較嚴重,工作不好找,雖然軟體專業要找一份工作還是比較容易,但好工作的機會少了很多,再多學習幾年,規避下風險;

深入理解計算機系統_3e 第四家庭作業(部分) CS:APP3e chapter 4 homework

ray design sed copy default ror this 處理 implement 4.52以後的題目中的代碼大多是書上的,如需使用請聯系 [email protected] 流水線部分只寫了偶數題號的,這幾天太浮躁,落下了好多課。。。 4.

深入理解計算機系統——第一學習筆記

資訊就是位+上下文 計算機系統中的所有的資訊都是用一串位bit 表示;區別不同資料物件的唯一方法就是這些資料物件時的上下文。 程式編譯過程 1.前處理器將 #include 部分轉換為相應檔案插入到源程式,輸出.i 檔案。 2.編譯器將 .i 編譯為組合語言 .s 檔案。 3.彙編器將.s 翻譯成機器語

<深入理解計算機系統(第三版)》第一

第一章 計算機系統漫遊 計算機系統是由硬體和系統軟體組成的,它們共同工作來執行應用程式. 1.1 資訊就是位+上下文 源程式實際上就是由一個值0和1組成的位(bit)序列,8個位被組織成一組,稱為位元組.每個位元組表示程式中某個文字字元. 大部分現代系統都是有ASCII標準表示文字字元,只由ASCII字

深入理解計算機系統第一學習筆記

1 一個程式的編譯過程 預處理階段:將程式中include的系統檔案插入程式文字中。 編譯階段:編譯器將hello.i翻譯成組合語言程式。 彙編階段:彙編器將hello.s翻譯成機器語言指令,生成二進位制檔案hello.o。 連結階段:將標準庫中的函式連結進來,生成可執行檔案h

深入理解計算機系統————第一筆記

計算機系統是由硬體和系統軟體組成,他們共同工作來執行應用程式,這本書的目的就在於幫助人們理解·當系統在執行hello程式時,系統發生了什麼以及為什麼會這樣,換句話說,當執行簡單程式hello時,整個電腦系統從應用程式,作業系統,快取裝置,等等,在這個程式執行的過程中做了什麼,以及為什麼會這樣

深入理解計算機系統隨筆】第一

1、處理器的指令集架構和處理器的微體系結構應當分開 指令集架構描述的是每條機器程式碼指令的效果,ISA在CPU硬體和軟體之間提供了一個抽象層,對於CPU設計者來講,ISA是一種設計的規範和依據,對於編譯器設計者來講,亦然,知道了CPU採用的ISA,就可以知道自

深入理解計算機系統----第一計算機系統漫遊

轉載地址 https://www.jianshu.com/p/f0fd1473344e   資訊的表示 資訊就是位+上下文,系統中的所有資訊,包括磁碟檔案,程式,儲存器中資料以及網路傳輸的資料,都是一串位表示的.區分不同資料物件的唯一方法就是判斷其上下文. 比如11011101

深入理解計算機系統-第一-計算機系統漫遊

shell是一種命令列直譯器,它輸出一個提示符,等待你輸入一行命令,然後執行這個命令 系統的硬體組成 儲存器分層結構的主要思想是一個層次上的儲存器作為下一層次的儲存器的快取記憶體。所以暫存器堆就是L1的快取記憶體,L1就是L2的快取記憶體,L2就是主存的告訴快取

深入理解計算機系統》讀書筆記(第一

主要內容 0.計算機系統是由硬體和系統軟體組成的,它們共同工作來執行應用程式。 1.程式是怎樣編譯執行。 2.程序,執行緒,虛擬記憶體,檔案等基本概念。 3.本書內容提前瀏覽。 資訊就是位+上下文 本書用了一個hello.c的表示方法說明了一個思

深入理解計算機系統-作業2.10

oid 位置 pla borde 作業2 nbsp body 開始 width 1 void inplace_swap(int *x, int *y){ 2 *y = *x ^ *y;/*step1*/ 3 *x = *x ^ *y;/*step2*/ 4