| 屬性 | exit() | return |
|---|---|---|
| **作用範圍** | 終結**整個進程** | 返回**當前函式** |
| **控制權移交** | 交給**作業系統** | 交給**呼叫函式** |
| **層級** | 系統呼叫/執行期庫函式 | 語言關鍵字/編譯器指令 |
| **清理動作** | 刷新 I/O 緩衝區、呼叫 `atexit` 登記函式、釋放進程資源 | 展開棧幀、呼叫區域物件解構函式 (C++) |
| **main 中行為** | 等價於 `return`(但更徹底) | 正常結束程式,回傳值給 OS |
| **參數** | `int status`:0 成功,非 0 失敗 | 函式回傳型別對應值 |
#include // C
// 或 #include // C++
void exit(int status);
#include
#include
struct A { ~A() { puts("~A()"); } };
void deep() {
A a; // 區域物件
exit(0); // 直接結束進程
// ~A() **不會**執行!
}
int main() {
deep();
return 0; // 不會執行到這裡
}
輸出:無輸出(`~A()` 被跳過)。若改 `return`,會印出 `~A()`。
struct A { ~A() { puts("~A()"); } };
void deep() {
A a;
return; // 正常返回
// ~A() **會**執行
}
int main() {
deep();
puts("after deep");
return 0;
}
輸出:
~A() after deep
int main() {
// ... 程式邏輯
return 0; // 編譯器隱式插入 exit(0) 類似邏輯
}
C/C++ 標準規定:`main` 結束(`return` 或落底)會呼叫 `exit` 等價邏輯,**但先正確解構區域物件**。
| 函式 | 清理動作 | 用途 |
|---|---|---|
| `exit()` | 完整:atexit、流刷新、靜態物件解構 | 正常結束 |
| `_Exit()` (C99) / `_exit()` (POSIX) | **無**:僅進程結束,不刷新流、不呼叫 atexit/解構函式 | 嚴重錯誤、fork 後子進程、信號處理器中 |
| `abort()` | 無,產生核心傾印(core dump) | 不可恢復錯誤、斷言失敗 |
| 場景 | 推薦 | 理由 |
|---|---|---|
| main 正常結束 | `return 0;` | 語意清晰、保證 RAII |
| main 異常結束 | `return EXIT_FAILURE;` | 可攜性、標準宏 |
| 深層巢狀函式遇到不可恢復錯誤 | `exit(EXIT_FAILURE)` | 一鍵跳出所有層級 |
| 庫函式/供他人呼叫的函式 | **回傳錯誤碼** | 不決定進程生死,交由呼叫端決策 |
| fork() 後子進程 | `_exit()` | 避免雙重刷新流、雙重 atexit |
| 信號處理器中 | `_Exit()` / `_exit()` | 非同步安全、避免死鎖 |
| C++ 區域物件持有資源(鎖、檔案) | **禁止 `exit()`** | 會導致資源洩漏、死鎖 |
「`exit(0)` 和 `return 0` 在 main 裡一樣」
❌ **不完全一樣**。`exit(0)` 會**跳過** `main` 內區域變數的解構函式;`return 0` 會正確執行。若 `main` 有 RAII 物件(`std::ofstream`、`std::lock_guard` 等),**必須用 `return`**。
「`exit` 能讓物件正確解構」
❌ **只有靜態/全域物件**會解構。**區域(自動儲存期)物件不會**。