1972-C語言重寫Unix:一場異端的可攜性革命#
案件摘要#
1972 年,貝爾實驗室的 Dennis Ritchie 做了一件當時被視為異端的事:用高階語言 C 重寫作業系統 Unix。當時的教科書都說 OS 必須用組合語言寫——Ritchie 證明他們錯了,並讓 Unix 從此獲得「可移植」的生命。
前因 -- 為什麼會有這個案子#
- Unix 的誕生:1969 年 Ken Thompson 在貝爾實驗室的廢棄 PDP-7 上寫出第一版 Unix(組合語言)。1971 年移植到 PDP-11,但仍受制於組語——換一種 CPU 就要全部重寫。
- 當時的教條:1970 年代主流觀點認為作業系統必須手寫組合語言,因為需要精確控制暫存器、記憶體位址與硬體中斷。高階語言(如 FORTRAN)的執行效率與底層控制被認為不足以勝任。
- BCPL 與 B 語言的伏筆:Thompson 先以 Martin Richards 的 BCPL 為本簡化出 B 語言(無型別、直譯式)嘗試重寫 OS,但 B 的效率不足(word-addressed、無 byte 型別)。Ritchie 在 1971–72 年間為 B 加入型別(int、char、指標)、編譯成機器碼,誕生 New B → C 語言。
- PDP-11 的硬體特性:PDP-11 有 byte 定址、豐富的定址模式,剛好適合 C 的指標語意——硬體與語言在此刻天作之合。
線索與推理 -- 數學式、程式、理論#
為何用高階語言寫 OS 是異端#
當時的反對理由:OS 需要 (1) 精確的記憶體位址操作、(2) 中斷處理、(3) 極致效能。Ritchie 的解法是讓 C 同時具備三者: - 指標:C 的指標就是位址,*p 直接對映記憶體操作,可寫裝置驅動器 - 低階存取:可內嵌組語(inline asm)處理極少數無法表達的指令 - 接近組語的效能:C 的設計原則是「每個語言結構對應極少量機器指令」,編譯器不隱藏成本
C 與組合語言的對照範例#
以「複製字串」為例:
; PDP-11 組合語言版本
MOV #SRC, R1 ; R1 = 來源位址
MOV #DST, R2 ; R2 = 目的位址
LOOP: MOVB (R1)+, (R2)+ ; 位元組複製,指標遞增
BNE LOOP ; 非零則繼續
HALT
/* C 語言版本(可移植到任何 CPU) */
void strcpy(char *dst, const char *src) {
while ((*dst++ = *src++))
; /* 複製直到 '\0' */
}
兩者幾乎一一對應,但 C 版可編譯到 PDP-11、VAX、任何機器。效能犧牲趨近於零,可移植性獲得無限大——這正是這場革命的本質:
\[ \text{Value} = \frac{\text{Portability} \to \infty}{\text{Performance loss} \to 0} \]
Portability 的革命#
- 1972–73:Ritchie 重寫 Unix 核心,1973 年第四版 Unix 已有 95% 以上是 C(僅少數底層仍是組語)。
- 1977–78:Unix 首度移植到 Interdata 8/32,證明「一次編寫、處處執行」。隨後移植到 VAX,誕生 32-bit 的 32V,成為 BSD 系的祖先。
- 可移植性的數學意義:若 OS 有 \(n\) 個模組、面對 \(m\) 種 CPU:
\[ \text{組語成本} = n \times m, \quad \text{C 成本} = n + m \quad (\text{只需 } m \text{ 個編譯器}) \]
從乘法到加法——這是軟體工程的線性化革命,與分封交換之於通訊、PageRank 之於搜尋同構。
C 編譯器作為系統軟體基石#
C 編譯器本身也是「自我編譯」(self-hosting):用 C 寫 C 編譯器,然後用舊編譯器編譯新編譯器。這個自舉(bootstrapping)過程:
舊編譯器 (C) → 編譯新編譯器原始碼 (C) → 新編譯器
↑ │
└────────── 自舉閉環 ←───────────────┘
C 編譯器從此成為每個新平台的「第一塊基石」:先移植 C 編譯器,整個 Unix 生態(shell、工具鏈、應用)就能跟著移植。
Unix + C 的共生體系#
語言、shell、工具鏈構成三位一體:
| 層 | 元件 | 語言 |
|---|---|---|
| 核心(kernel) | 行程、記憶體、檔案系統 | C(+少量組語) |
| Shell | 命令解譯、管線 | C |
| 工具鏈 | compiler(cc)、grep、awk、sed | C |
| 應用 | ed、vi、一切 | C |
Unix 哲學「小工具組合」用管線實現:
$ cat access.log | grep "404" | awk '{print $1}' | sort | uniq -c | sort -rn
每個工具只做一件事、以純文字流(stdin/stdout)介接——這種「組合式設計」影響了後世所有軟體架構,從 Unix 管線到函數式程式設計的資料流皆然。
結案 -- 後果與影響#
- Unix 家族開枝散葉:BSD、System V、SunOS、AIX、HP-UX 皆為 C 重寫 Unix 的子孫;1978 年《The C Programming Language》(K&R)出版,C 成為系統程式設計的標準語言。
- 1983 年 ANSI C 標準化、1989 年 C89 標準發布,C 成為跨平台的事實標準。
- 對現代 OS 的直接影響:
- Linux 核心:以 C 語言寫成(GCC 編譯),是 Unix 可攜革命的直系繼承者
- macOS:核心 XNU 為 Mach(C)+ BSD(C)混合
- Windows NT 核心:Dave Cutler 團隊以 C 語言開發,可移植到 x86、Alpha、MIPS
- 幾乎所有現代語言的直譯器與編譯器(Python、Ruby、Go、Rust 的初期工具鏈)皆以 C 實作——C 是「語言之母」。
- Ritchie 於 1983 年與 Thompson 同獲圖靈獎,表彰 Unix 與 C 對系統軟體的奠基貢獻。
關鍵人物與文獻#
- Dennis Ritchie:〈The Development of the C Language〉(1993)、C 語言之父
- Ken Thompson:Unix 原創者、B 語言、UTF-8(晚期貢獻)
- Brian Kernighan & Dennis Ritchie:《The C Programming Language》(1978,K&R)
- Martin Richards:BCPL(1966)——C 的祖父
- AT&T 貝爾實驗室:1956 反壟斷協定無意間促成 Unix 原始碼流向學術界