CS:APP 電腦系統:程式設計師的角度 第二章之一-Information Storage筆記
二進制非常適合機器來儲存以及處理訊息,而且有很多方式可以輕鬆的表達二進制,例如:
punched card
上的洞- 線上的高低電壓
- 磁場的順時針與逆時針
二進制有以下三種常見的表示數字方式:
Unsigned
Two's-complement
Floating-point
一些特性
- 用
32bit
的int
來計算以下算式會溢出變為負數,
這和電腦如何表示以及儲存數字有關
$200 * 300 * 400 * 500 = -884,901,888$
- 浮點數運算並沒有
associative
(結合律)因為有限精度 - 雖然會有期待之外的結果,但這些結果是可預測的,熟知這些電腦數字運算的特性對於寫程式有極大的幫助,可以避免
bug
以及安全問題產生
- 電腦使用
blocks
來當記憶體的最小單位,通常是8bits
,1byte
,也就是每個地址是一個區塊 Machine-level program
把記憶體視為一個很大的bytes
陣列,稱之為virtual memory
- 記憶體每個
byte
都有其唯一標示,稱為address
(位址),這些所有的位址稱之為virtual address space
virtual address space
是給machine-level program
看的,事實上他是由各種記憶體(DRAM, flash memory, disk, special hardware)實作而成,為了給程式一個單純的byte array
使用
16進制
- 二進制冗長,通常使用
16
進制 - 在
C
語言中0x
或0X
開頭的是16
進制,後面的字母可以是大寫或小寫或是大小寫混合,例如:0xFA1D37B
0xfa1d37b
0xFa1D37b
都是合法的
- 可以記住
A
、C
、以及F
分別代表多少來快速運算16->10
進制或其他
0x173A4C轉換為10進制只要把全部拆開換成二進制就可以
反之,二進制四個一組轉換為16
進制,如果剛好不是四的倍數,最左邊剩幾個就幾個一組,然後前面補0
資料大小
- 每個電腦都有
word size
,是pointer
的大小 w-bit word size
的電腦,virtual addresses
的範圍是$0\text{\textasciitilde}2^w - 1$,給程式最多$2^w$bytes
32-bits word size
的virtual address space
最多只有4GB(4 x 10^9bytes)
,而64-bit
可以到$1.84 \times 10^{19}$bytes
- 大多
64
位元機器也能執行給32
位元機器執行的程式,但64
位元編譯的只能給64
位元用,編譯方法不同 C
語言支援不同格式的integer
和floating point data
ISO C99
統一資料大小,無論哪個編譯器或是機器設定- 大多資料型態都是
signed
,除非聲明unsigned
char
在C
標準中沒有明確被定義為應該存有符還是無符的數值。工程師應該聲明為signed char
來保證1-byte signed value
,雖然很多時候char
的有符或無符並不會影響程式- 以下聲明完全相同
- unsigned long
- unsigned long int
- long unsigned
- long unsigned int
- 工程師應致力於寫出具可移植性的
code
,例如避免程式對於資料的最大值敏感;以前32
位程式時常用int
儲存指針,但是這個方法在64
位會導致問題。至於確切的前因後果書上並未收錄,至少在這邊的原文沒寫
Addressing and Byte Ordering
- 有些機器會把物件在記憶體裡從
LSB(Least significant bit)
排到MSB
,這樣的方式稱為little endian
,反過來就是big endian
例如在位址0x100
有數值0x01234567
,可以排成以下兩種
Intel-compatible machines
通常採用little endian
,而IBM
和Oracle
則是大多採用big endian
,現在的微處理器很多採用bi-endian
,可以使用任意一種模式ARM
微處理器可以用little
或是big
,而Android(Google)
和IOS
則是只用little-endian
- 兩種模式沒有正確與否,只是一種選擇
那,知道這個有什麼用?
的確,對於現在的程式設計師,幾乎無所謂,但有時候還是會造成問題
- 兩個不同模式的機器透過網路傳遞資料,就會造成字節順序錯亂 - 章節
11
會舉例說明 - 以字節來看資料,例如以下
4004d3: 01 05 43 0b 20 00
add %eax,0x200b43(%rip)
byte
反過來了
- 第三種情況比較特殊,當程式想要跳出平常的資料型態,在
C
中可以用cast
或是union
to allow an object to be referenced according to
a different data type from which it was created(這段有看沒有懂),但這個小技巧在開發應用程式大多數時候是強烈建議不要使用,但有時候在系統層的程式編寫會很好用
以下程式可以用來顯示bytes
在以下機器執行:
- Linux 32: Intel IA32 processor running Linux.
- Windows: Intel IA32 processor running Windows.
- Sun: Sun Microsystems SPARC processor running Solaris. (These machines
are now produced by Oracle.) - Linux 64: Intel x86-64 processor running Linux
可以看到int
和float
在不同的系統與處理器中有字節序的不同,linux32
、windows
以及linux64
都是使用little-endian
,也就是LSB
放在最前面;Sun
則是相反
最後的位址,Linux64
和大家都不同,因為他使用的是8 byte
位址
把12345
的int
與float
轉為二進制發現有一段是一樣的,這不是巧合,詳細會在浮點數格式章節說明
C
的String
則是an array of characters
終止於null
冷知識:
Unicode
標準收錄了超過十萬個字,支援古埃及與巴比倫文字,但Universal Technical Committee
拒絕了把克林貢語(星際大戰中的虛構語言)加入的提案
Boolean Algebra
- 是電腦邏輯的基礎,使得我們可以精確的描述與分析電腦系統的行為
- 還能作為遮罩使用,過濾掉各種
signals
,詳細在第八章會講解
Bit-level Operations in C
C
語言支援位元運算
以下是不用第三個變數就可以直接交換兩個數字的炫技方式,這樣做不會有任何效能上的提升,單純好玩
Logical Operations in C
||
&&
!
||
以及&&
如果在第一個argument
就可以確定,就不會看第二個argument
了,例如:a && 5/a
p && *p++
Shift Operations in C
x << k
,出界的捨棄,後面的空位補零x >> k
,通常支援以下兩種右移- Logical: 右移後左邊空位補零
- Arithmetic: 右移後左邊補上原本的
MSB
(對signed integer
很有用)
C
並沒有規定右移signed numbers
時應該使用哪種右移(當遇到有符數字時,幾乎所有編譯器/機器都使用arithmetic
右移,而無符就用logical
)Java
對於右移有明確規定x >> k
shifts x arithmetically by k positionsx >>> k
shifts logically
C
沒有明確規定當移動超過word size
的時候該怎麼辦,通常都是取k mod w
,但還是不建議C
的工程師移動超過word size
;相反的,Java
有定義一定要取mod
,所以可以放心移動超過word size
小知識: 1<<2 + 3<<4在
C
中會變成(1 << (2+3)) << 4
,而不是(1<<2) + (3<<4)
。在C
中弄清楚優先順序很重要,如果不確定就加括號就對了!
CS:APP 電腦系統:程式設計師的角度 第二章之一-Information Storage筆記
https://f88083.github.io/2024/03/05/CS-APP-電腦系統-程式設計師的角度-第二章之一-Information-Storage筆記/