| 特性 | exit() | _exit() / _Exit() |
|---|---|---|
| 所屬層級 | C 標準庫 (glibc) | 系統調用封裝 (unistd.h) |
| 執行清理 | ✅ 刷新 stdio 緩衝區、關閉串流、執行 atexit/on_exit 註冊函數 | ❌ 直接進入內核,跳過所有用戶態清理 |
| 檔案描述符 | 關閉所有打開的串流(間接關閉 fd) | 內核自動關閉所有 fd |
| 臨時檔案 | 清理 tmpfile() 建立的臨時檔 | 不清理,可能殘留 |
| 適用場景 | 正常程式結束、main 返回 | fork 後子進程錯誤退出、嚴重錯誤立即終止、信號處理函數中 |
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("output begin\n");
printf("content in buffer"); // 無換行,留在緩衝區
exit(0);
}
輸出:
output begin
content in buffer
#include <stdio.h>
#include <unistd.h>
int main() {
printf("output begin\n");
printf("content in buffer"); // 無換行
_exit(0);
}
輸出:
output begin
解釋:_exit() 直接觸發 exit_group 系統調用,標準輸出緩衝區未刷新,"content in buffer" 丟失。
atexit() 註冊的函數(後進先出)on_exit() 註冊的函數fflush(NULL))fcloseall())tmpfile() 建立的臨時檔_exit() 進入內核SIGCHLD 給父進程SIGHUP 給前台進程組EXIT_ZOMBIE,等待父進程 wait()main() 函數返回(編譯器隱式插入)exec() 前發生錯誤(避免雙重刷新緩衝區、雙重執行 atexit)// 錯誤:子進程用 exit()
pid = fork();
if (pid == 0) {
if (setup_failed) exit(1); // 危險!雙重刷新父進程緩衝區
exec(...);
}
// 正確:子進程用 _exit()
pid = fork();
if (pid == 0) {
if (setup_failed) _exit(1); // 安全,直接進內核
exec(...);
}
exit(int status):標準 C_Exit(int status):C99 標準,行為同 _exit(),不保證系統調用名稱_exit(int status):POSIX,直接系統調用abort():產生 SIGABRT,生成 core dump,不執行清理quick_exit():C11,執行 at_quick_exit() 註冊函數,再 _Exit()