ฟังก์ชัน atexit() ใช้ลงทะเบียนฟังก์ชันที่จะถูกเรียกเมื่อโปรแกรมจบอย่างปกติ (Normal Termination) ผ่าน exit() หรือ return จาก main() อยู่ใน Header <stdlib.h>
ไวยากรณ์
#include <stdlib.h>
int atexit(void (*func)(void));
func- Pointer to Function ที่ไม่รับ Parameter และไม่คืนค่า (void func(void))- คืนค่า: 0 = สำเร็จ, Non-zero = ล้มเหลว (Registry เต็ม)
- สามารถลงทะเบียนได้สูงสุด
ATEXIT_MAXฟังก์ชัน (มากกว่า 32 ตัว)
ตัวอย่าง
#include <stdio.h>
#include <stdlib.h>
void func1(void) {
printf("\nExit of function 1");
}
void func2(void) {
printf("\nExit of function 2");
}
int main() {
atexit(func1); // Register func1
printf("\nStarting of main()");
atexit(func2); // Register func2
printf("\nEnding of main()");
return 0; // เรียก func2 แล้ว func1 (LIFO)
}
ผลลัพธ์
Starting of main()
Ending of main()
Exit of function 2
Exit of function 1
คำอธิบาย: LIFO Order (Last In, First Out)
ฟังก์ชันที่ลงทะเบียน ทีหลังจะถูกเรียกก่อน (Stack-like)
atexit(A); // 1st registered
atexit(B); // 2nd registered
atexit(C); // 3rd registered
// Exit Order: C → B → A
การใช้งานจริง: Resource Cleanup
#include <stdio.h>
#include <stdlib.h>
FILE *logFile = NULL;
void cleanupLog() {
if (logFile) {
fprintf(logFile, "Program terminated normally\n");
fclose(logFile);
logFile = NULL;
}
}
void initLog() {
logFile = fopen("app.log", "a");
if (logFile) {
atexit(cleanupLog); // Ensure cleanup on exit
fprintf(logFile, "Program started\n");
}
}
int main() {
initLog();
// ... program logic ...
return 0; // cleanupLog() จะถูกเรียกอัตโนมัติ
}
atexit() vs at_quick_exit() (C11)
| ฟังก์ชัน | เรียกเมื่อ | เรียก Destructors | Handlers |
|---|---|---|---|
atexit() | exit() หรือ return from main | ✓ ใช่ | atexit Handlers |
at_quick_exit() | quick_exit() | ✗ ไม่ | at_quick_exit Handlers |
ข้อจำกัดและข้อควรระวัง
- Handlers ต้องเป็น
void func(void)- ไม่รับ Parameter, ไม่คืนค่า - ไม่สามารถ Deregister (Unregister) Handler ได้
- ถ้า
exit()ถูกเรียกหลายครั้ง (เช่นใน Handler) → Undefined Behavior - ไม่ทำงานถ้าโปรแกรมจบด้วย
_Exit(),abort(), หรือ Signal ที่ไม่ Handle - C++: Static Objects Destructors เรียก หลัง atexit Handlers (Reverse Order of Initialization)
C++ Alternative: RAII
#include <fstream>
#include <memory>
class LogFile {
std::ofstream file;
public:
LogFile(const char* name) : file(name, std::ios::app) {
if (file) file << "Program started\n";
}
~LogFile() {
if (file.is_open()) {
file << "Program terminated normally\n";
file.close();
}
}
};
int main() {
LogFile log("app.log"); // Destructor เรียกอัตโนมัติเมื่อ main จบ
// ... program logic ...
return 0;
}
สรุป
atexit() เหมาะสำหรับ C-Style Cleanup (Files, Sockets, Shared Resources) ใน C++ ควรใช้ RAII (Destructors) ซึ่งปลอดภัยกว่าและ Exception-safe