---
# System prepended metadata

title: 副程式與巨集：簡單明瞭的比較

---

副程式與巨集：簡單明瞭的比較**  

在微處理機的程式設計中，我們會發現有些程式碼會重複出現，這時我們可以使用 **副程式** 或 **巨集** 來簡化程式，讓它更容易閱讀和管理。那麼，這兩者有什麼不同呢？讓我們用簡單的方式來理解！  

---

### **1. 副程式（Subroutine）—— 像是「工廠」**
**概念**：副程式是一段可以重複使用的程式碼，我們可以在主程式中「呼叫」它，然後執行完畢後回到主程式。  

**比喻**：  
- 想像你在家裡有一台「餅乾工廠」，每次想要餅乾時，你不需要自己動手做，只要按一下按鈕，工廠就會幫你做好並送來。  
- 同樣地，當程式需要執行某個功能時，就可以「呼叫」副程式，副程式執行完後，再回到主程式繼續執行其他指令。  

**特點**：  
✔ 節省記憶體（只需要一份程式碼）  
✔ 可以多次重複呼叫  
✔ 執行時會「跳過去」，結束後「跳回來」  

**例子（組合語言）**：
```assembly
CALL PRINT_MESSAGE  ; 呼叫副程式
...
PRINT_MESSAGE:
    MOV DX, OFFSET MESSAGE
    CALL DISPLAY
    RET  ; 回到主程式
```

---

### **2. 巨集（Macro）—— 像是「食譜」**
**概念**：巨集是一種「事先寫好的指令組」，在程式編譯時，會直接展開並插入到程式中，就像是一份「固定食譜」，每次需要時都會重新複製一份來用。  

**比喻**：  
- 如果你有一份「餅乾食譜」，每次想要餅乾時，你都要自己按照食譜製作一次，每次做的餅乾都是獨立的，不會回去問工廠要。  
- 在程式中，每次用到巨集，編譯器都會把這段程式碼複製到該處，而不是跳去執行它。  

**特點**：  
✔ 執行速度較快（不用跳來跳去）  
✔ 但是會讓程式碼變長（每次都要複製一份）  
✔ 不能像副程式那樣「回到主程式」，因為它只是單純展開指令  

**例子（組合語言）**：
```assembly
MACRO PRINT_MESSAGE
    MOV DX, OFFSET MESSAGE
    CALL DISPLAY
ENDM

PRINT_MESSAGE  ; 這裡會直接插入巨集的內容
```

---

### **3. 副程式 vs. 巨集：哪個比較好？**
| 比較項目 | 副程式（Subroutine） | 巨集（Macro） |
|---------|----------------|--------------|
| **程式碼大小** | 節省空間（只寫一次） | 會變大（每次複製） |
| **執行速度** | 可能較慢（需要跳轉） | 較快（不用跳轉） |
| **適合用途** | 適合重複使用但不要求速度的程式 | 適合小段程式且要求速度的情況 |

---

### **4. 小結**
- **副程式** 是一個「可以呼叫的程式」，適合重複使用但不佔太多空間。  
- **巨集** 是「展開的程式碼」，不需要跳轉但會讓程式變長。  
- 何時使用？**如果要節省記憶體，選副程式；如果要更快執行，選巨集。**  

這樣你能夠理解副程式與巨集的不同了嗎？

## **副程式 (Subroutine) 與巨集 (Macro) 的完整比較教學**

在微處理機程式設計中，「副程式 (Subroutine)」和「巨集 (Macro)」是兩種**提高程式碼重用性**的重要技術。兩者的主要目標都是**減少程式碼重複、提升可讀性與維護性**，但它們的運作方式、效率與應用場景卻有所不同。本文將透過**定義、運作方式、優缺點比較、適用情境與實作範例**來幫助學生完整理解這兩種技術。

---

## **1. 副程式 (Subroutine)**
### **(1) 副程式的定義**
副程式是一段可重用的程式碼，具有**獨立的程式區塊**，可在主程式中透過**CALL 指令**呼叫，執行完畢後再透過**RETURN 指令**返回主程式。副程式可以減少程式碼重複，使程式結構更清晰。

### **(2) 副程式的運作方式**
- 當程式執行到 **CALL 指令**，會將**返回位址**存入**堆疊 (Stack)**，然後跳轉到副程式執行。
- 副程式執行完畢後，遇到 **RETURN 指令 (RET)**，會從堆疊中取回返回位址，繼續執行主程式的後續指令。

### **(3) 副程式的優缺點**
✅ **優點**：  
- **節省記憶體**：程式碼只存放一次，每次呼叫時只需跳轉，不會重複插入程式碼。  
- **適用於大型程式**：可拆解為多個模組，提高可讀性與維護性。  
- **支援參數傳遞**：可使用暫存器或堆疊來傳遞不同的輸入值，使副程式更靈活。  

❌ **缺點**：  
- **執行時會有額外的時間開銷**：呼叫副程式時需要 **壓入與彈出堆疊 (PUSH/POP)**，會消耗 CPU 時間。  
- **需要額外的堆疊空間**：如果頻繁呼叫副程式，可能導致 **堆疊溢位 (Stack Overflow)**。  

### **(4) 副程式的範例**
🔹 **使用 CALL/RET 指令的副程式 (8086 組合語言)**
```assembly
MAIN:
    MOV AX, 5         ; 將 5 放入 AX
    MOV BX, 10        ; 將 10 放入 BX
    CALL ADDITION     ; 呼叫副程式 ADDITION
    HLT               ; 停止執行

ADDITION:
    ADD AX, BX        ; AX = AX + BX
    RET               ; 返回主程式
```
這段程式執行後，AX 內的值會變成 15，然後回到 `MAIN` 繼續執行。

---

## **2. 巨集 (Macro)**
### **(1) 巨集的定義**
巨集是一段 **可重用的指令集合**，在**組譯 (Assembly) 時**，會被展開並**直接插入程式碼中**。這與副程式不同，因為副程式的程式碼只存在一份，而巨集的程式碼則會被展開並重複插入每個使用的地方。

### **(2) 巨集的運作方式**
- **在組譯 (Compile) 時期執行展開**，而不是在執行時才呼叫，因此不會有 **CALL/RET 指令** 的時間開銷。
- 每次使用巨集時，組譯器會將其**完整展開**，使程式碼變長，但執行時不會有副程式呼叫的額外開銷。

### **(3) 巨集的優缺點**
✅ **優點**：  
- **執行速度較快**：因為是**直接展開**，不需要 CALL/RET 指令，也不會影響堆疊。  
- **適用於小型、簡單的功能**：例如單純的 I/O 指令、數學運算等。  

❌ **缺點**：  
- **增加程式碼大小**：每次使用巨集，組譯器都會展開一次，導致程式碼變長 (Code Bloat)。  
- **不適合複雜功能**：巨集不支援堆疊處理與參數傳遞，功能相對簡單。  

### **(4) 巨集的範例**
🔹 **使用巨集的程式 (8086 組合語言)**
```assembly
MACRO ADDITION X, Y
    MOV AX, X
    ADD AX, Y
ENDM

MAIN:
    ADDITION 5, 10   ; 巨集展開後會變成 MOV AX, 5 / ADD AX, 10
    HLT              ; 停止執行
```
在組譯時，這段程式碼會直接展開，等效於：
```assembly
MAIN:
    MOV AX, 5
    ADD AX, 10
    HLT
```
可以看到，巨集的**程式碼直接插入**，不需要 CALL/RET。

---

## **3. 副程式與巨集的比較**
| **比較項目**  | **副程式 (Subroutine)** | **巨集 (Macro)** |
|--------------|------------------|--------------|
| **定義方式** | 透過 `CALL` 指令呼叫，使用 `RET` 返回 | 直接在組譯時展開 |
| **執行效率** | 需要 `CALL` 和 `RET`，有額外的 CPU 開銷 | 無需呼叫，執行速度較快 |
| **記憶體使用** | 只存一次，呼叫時跳轉，不會重複佔用空間 | 每次使用都會展開，程式碼變長 |
| **適用場景** | 適合大型程式、需多次重用的功能 | 適合小型功能，如 I/O、簡單計算 |
| **支援參數傳遞** | 可透過堆疊或暫存器傳遞參數 | 參數在組譯時展開，無法動態變更 |
| **維護性** | 只需修改副程式本體 | 需要修改所有展開的程式碼 |

---

## **4. 什麼時候該用副程式？什麼時候該用巨集？**
✅ **使用副程式的情境**：  
- **需要多次重用** (如數學運算、I/O 處理)  
- **程式碼較長，無法重複插入** (如驅動程式、通訊協定)  
- **需要參數傳遞與返回值**  

✅ **使用巨集的情境**：  
- **程式碼簡短，執行效率重要** (如 LED 開關控制)  
- **指令較少，避免 CALL/RET 的額外負擔** (如組態設定)  

---

## **5. 總結**
1. **副程式 (Subroutine)** 透過 CALL/RET 呼叫，**節省記憶體但執行速度較慢**，適合**大型程式與需多次呼叫的功能**。  
2. **巨集 (Macro)** 在組譯時直接展開，**執行速度快但會增加程式碼大小**，適合**短小的功能模組**。  
3. **副程式適合動態運行，巨集適合靜態展開**，在程式設計時應根據需求選擇合適的方法。

透過這樣的比較，大學生可以清楚理解副程式與巨集的差異，並在程式設計時作出正確選擇。