Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> การเขียนโปรแกรม C

ฟังก์ชัน atexit() ใน C/C++: ลงทะเบียนฟังก์ชัน Cleanup ตอนจบโปรแกรม

ฟังก์ชัน 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)

ฟังก์ชันเรียกเมื่อเรียก DestructorsHandlers
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