深入理解計算機系統第二章——信息的表示和處理
2.1 信息存儲
- 8位的塊或者字節作爲最小的可尋址的內存單位
- 機器級程序將內存視爲一個非常大的字節數組 / 虛擬內存
- 內存的每個字節都由一個唯一的數字來標識,稱爲它的地址,所有可能地址的集合就稱爲虛擬地址空間
- 例如,C語言中一個指針的值(無論它指向一個整數、一個結構或是某個其他程序對象)都是某個存儲塊的第一個字節的虛擬地址。C編譯器還把每個指針和類型信息聯繫起來,這樣都可以根據指針值的類型,生成不同的機器級代碼來訪問存儲在指針所指向位置處的值
- 每個程序對象可以簡單地視爲一個字節塊,而程序本身就是一個字節序列
2.1.1 十六進制表示法
- 用十六進制(hexadecimal)數來表示位模式。用十六進制書寫,一個字節的值域爲0016 ~ FF16
- x = 2n,當n表示成 i + 4j (其中0≤i≤3)的形式,可以把x寫成開頭的十六進制數爲 i ,後面跟着 j 個十六進制的0。比如,x=2048=211,我們有n=11=3+4×2,從而得到十六進制表示0x800
- x = q × 16 + r,然後我們用十六進制數字表示的 r 作爲最低位數字,並且通過對 q 反覆進行這個過程得到剩下的數字。例如,十進制314156的轉換:
- 314156 = 19634 × 16 + 12 (C)
- 19634 = 1227 × 16 + 2 (2)
- 1227 = 76 × 16 + 11 (B)
- 76 = 4 × 16 + 12 (C)
- 4 = 0 ×16 + 4 (4)
- 由此讀出十六進制表示爲0x4CB2C
2.1.2 字數據大小
- 對於一個字長爲 w 位的機器而言,虛擬地址的範圍爲 0 ~ 2w-1 ,程序最多訪問 2w 個字節
2.1.3 尋址和字節順序
-
排列表示一個對象的字節有兩個通用的規則:
小端法(little endian)—— 最低有效字節在最前面;
大端法(big endian)—— 最高有效字節在最前面; -
考慮一個 w 位的整數,其位表示爲 [ xw-1,xw-2,…,x1,x0 ],其中 xw-1 是最高有效位,而 x0 是最低有效位。假設 w 是8的倍數,這些位就能被分組成字節,其中最高有效字節包含位 [ xw-1,xw-2,…,xw-8 ],而最低有效字節包含位 [ x7,x6,…,x0 ],其他字節包含中間的位。某些機器選擇在內存中按照前一種規則從最低有效字節到最高有效字節的順序存儲對象;另一些機器按照後一種規則從最高有效字節到最低有效字節的順序存儲
-
假設變量 x 的類型爲 int,位於地址 0x100 處,它的十六進制值爲 0x01234567。地址範圍 0x100 ~ 0x103 的字節順序依賴於機器的類型:
(注意,在字 0x01234567 中,高位字節的十六進制值爲 0x01,低位字節的十六進制值爲 0x67)大端法 小端法 0x100 0x101 0x102 0x103 0x100 0x101 0x102 0x103 … 01 23 45 67 … … 67 45 23 01 … -
反彙編(disassembler)是一種確定可執行程序文件所表示的指令序列的工具
-
下面這段C代碼,使用強制類型轉換來訪問和打印不同程序對象的字節表示。用 typedef 將數據類型 byte_pointer 定義爲一個指向類型爲 “unsignedchar” 的對象的指針。這樣一個字節指針引用一個字節序列,其中每個字節都被認爲是一個非負整數。第一個例程 show_bytes 的輸入是一個字節序列的地址,它用一個字節指針以及一個字節數來指示。該字節數指定爲數據類型 size_t,表示數據結構大小的首選數據類型。show_bytes 打印出每個以十六進制表示的字節。C格式化命令 “%.2x” 表明整數必須用至少兩個數字的十六進制格式輸出
#include<stdio.h>
typedef unsigned char *byte_pointer;
void show_bytes(byte_pointer start, size_t len) {
size_t i;
for (i = 0; i < len; i++)
printf(" %.2x", start[i]);
printf("\n");
}
void show_int(int x) {
show_bytes((byte_pointer) &x, sizeof(int));
}
void show_float(float x) {
show_bytes((byte_pointer) &x, sizeof(float));
}
void show_pointer(void *x) {
show_bytes((byte_pointer) &x, sizeof(void *));
}
2.1.4 表示字符串
- C語言中字符串被編碼以一個 null(其值爲0)字符結尾的字符數組。以參數 “12345” 和 6(包括終止符)來運行例程 show_bytes,我們將得到結果 31 32 33 34 35 00
- 注意,十進制數字 x 的 ASCII 碼正好是 0x3x,而終止字節的十六進制表示爲 0x00
- 在使用 ASCII 碼作爲字符碼的任何系統上都將得到相同的結果,與字節順序和字大小規則無關。因而,文本數據比二進制數據具有更強的平臺獨立性
2.1.5 表示代碼
- 二進制代碼是不兼容的,二進制代碼很少的能在不同機器和操作系統組合之間移植
- 機器沒有關於原始程序的任何信息,除了可能有些用來幫助調試的輔助表以外。從機器角度來看,程序僅僅只是字節序列
2.1.6 布爾代數簡介
~ | NOT | 非 |
---|---|---|
& | AND | 與 |
| | OR | 或 |
^ | EXCLUSIVE-OR | 異或 |
- 位向量 a = [ 01101001 ] 表示集合 A = { 0,3,5,6 },而 b = [ 01010101 ] 表示集合 B = { 0,2,4,6 }。使用這種編碼集合的方法,布爾運算 | 和 & 分別對應於集合的並和交,而 ~ 對應於集合的補。運算 a&b=[ 01000001 ],而 A∩B={ 0,6 }
2.1.7&8&9 C語言中的運算
-
位級運算:
C的表達式 二進制表達式 二進制結果 十六進制結果 ~0x41 ~[ 0100 0001 ] [ 1011 1110 ] 0xBE ~0x00 ~[ 0000 0000 ] [ 1111 1111 ] 0xFF 0x69 & 0x55 [ 0110 1001 ] & [ 0101 0101 ] [ 0100 0001 ] 0x41 0x69 | 0x55 [ 0110 1001 ] | [ 0101 0101 ] [ 0111 1101 ] 0x7D -
邏輯運算:
表達式 結果 ! 0x41 0x00 ! 0x00 0x01 !! 0x41 0x01 0x69 && 0x55 0x01 0x69 || 0x55 0x01 -
移位運算:(算術右移是在左端補 k 個最高有效位的值)
操作 值 參數 x [ 0110 0011 ] [ 1001 0101 ] x << 4 [ 00110000 ] [ 0101 0000 ] x >> 4(邏輯右移) [ 0000 0110 ] [ 0000 1001 ] x >> 4(算術右移) [ 0000 0110 ] [ 1111 1001 ]
補充
- 關於移動 k ≥ w 位
- 未完待續