อะไรคือความแตกต่างระหว่าง exit () และ abort ()?


130

ใน C และ C ++ ความแตกต่างระหว่างexit()และabort()อย่างไร? ฉันกำลังพยายามยุติโปรแกรมหลังจากเกิดข้อผิดพลาด (ไม่ใช่ข้อยกเว้น)

คำตอบ:


116

abort()ออกจากโปรแกรมของคุณโดยไม่เรียกใช้ฟังก์ชันที่ลงทะเบียนโดยใช้atexit()ก่อนและไม่ต้องเรียกตัวทำลายวัตถุก่อน exit()ทำทั้งสองอย่างก่อนออกจากโปรแกรมของคุณ มันไม่เรียกตัวทำลายสำหรับวัตถุอัตโนมัติแม้ว่า ดังนั้น

A a;
void test() { 
    static A b;
    A c;
    exit(0);
}

จะทำลายaและbถูกต้อง แต่จะไม่เรียก destructors cของ abort()จะไม่เรียกว่าผู้ทำลายวัตถุทั้งสอง เนื่องจากเป็นเรื่องโชคร้ายมาตรฐาน C ++ จึงอธิบายถึงกลไกทางเลือกที่ช่วยให้มั่นใจได้ว่าการยุติอย่างถูกต้อง:

อ็อบเจ็กต์ที่มีระยะเวลาการจัดเก็บอัตโนมัติจะถูกทำลายทั้งหมดในโปรแกรมที่ฟังก์ชันmain()ไม่มีอ็อบเจ็กต์อัตโนมัติและเรียกexit()ใช้งาน การควบคุมสามารถโอนโดยตรงไปเช่นโดยการขว้างปาข้อยกเว้นที่ติดอยู่ในmain()main()

struct exit_exception { 
   int c; 
   exit_exception(int c):c(c) { } 
};

int main() {
    try {
        // put all code in here
    } catch(exit_exception& e) {
        exit(e.c);
    }
}

แทนที่จะโทรexit()ให้จัดเรียงรหัสนั้นthrow exit_exception(exit_code);แทน


2
+1 เนื่องจากในขณะที่ Brian R.Bondy ทำได้ดีคุณได้ยกปัญหาการยกเลิก / ออก (ไม่ใช่ตัวทำลายของสแต็กอ็อบเจ็กต์ที่เรียกว่า) และเสนอทางเลือกสำหรับกระบวนการ C ++ ที่เน้น RAII
paercebal

ฉันกำลังหาวิธีออกจากโปรแกรมโดยไม่ต้องโทรหา dtor และคำตอบของคุณคือสิ่งที่ฉันกำลังมองหา! ขอบคุณ
acemtp

แน่นอนว่าถูกต้องอย่างสมบูรณ์หากเป็นเรื่องสำคัญที่ผู้ทำลายวัตถุอัตโนมัติของคุณจะไม่ถูกเรียก :-)
Chris Huang-Leaver

สำหรับความรู้ของฉันความแตกต่างอีกอย่างหนึ่งระหว่างการออกและการยกเลิกคือการยกเลิกอาจ (ขึ้นอยู่กับการกำหนดค่าระบบปฏิบัติการ) นำไปสู่การสร้างดัมพ์หลัก
Dirk Herrmann

33

abortส่งสัญญาณ SIGABRT ออกเพียงแค่ปิดแอปพลิเคชันที่ทำการล้างข้อมูลตามปกติ

คุณสามารถจัดการกับสัญญาณการยกเลิกได้ตามที่คุณต้องการ แต่ลักษณะการทำงานเริ่มต้นคือการปิดแอปพลิเคชันด้วยรหัสข้อผิดพลาด

การยกเลิกจะไม่ทำการทำลายวัตถุของสมาชิกแบบคงที่และทั่วโลกของคุณ แต่จะออก

แน่นอนว่าเมื่อแอปพลิเคชันปิดอย่างสมบูรณ์ระบบปฏิบัติการจะเพิ่มหน่วยความจำและทรัพยากรอื่น ๆ ที่ไม่ได้ใช้งาน

ทั้งในการยกเลิกและการออกยกเลิกโปรแกรม (สมมติว่าคุณไม่ได้แทนที่ลักษณะการทำงานเริ่มต้น) รหัสที่ส่งกลับมาจะกลับสู่การปกครองที่เริ่มต้นใช้งานของคุณ

ดูตัวอย่างต่อไปนี้:

SomeClassType someobject;

void myProgramIsTerminating1(void)
{
  cout<<"exit function 1"<<endl;
}

void myProgramIsTerminating2(void)
{
  cout<<"exit function 2"<<endl;
}

int main(int argc, char**argv)
{
  atexit (myProgramIsTerminating1);
  atexit (myProgramIsTerminating2);
  //abort();
  return 0;
}

ความคิดเห็นที่:

  • หากยกเลิกเป็น uncommented: ไม่มีอะไรจะพิมพ์และ destructor ของ SomeObject จะไม่ถูกเรียกว่า

  • หากมีการแสดงความคิดเห็นเกี่ยวกับการยกเลิกดังข้างต้น: ผู้ทำลายวัตถุบางอย่างจะถูกเรียกคุณจะได้รับผลลัพธ์ต่อไปนี้:

ฟังก์ชันออก 2
ฟังก์ชันออก 1


ในที่นี้เรียกว่าฟังก์ชัน exit 2 แล้วฟังก์ชัน exit 1. gcc 4, Linux 2.6
strager

1
หน้า Man สำหรับ atexit ระบุว่า: "ฟังก์ชัน [ที่ลงทะเบียนโดยใช้ atexit] ถูกเรียกในลำดับย้อนกลับไม่มีการส่งผ่านอาร์กิวเมนต์"
strager

@strager ถูกต้องฟังก์ชันที่ลงทะเบียนโดย atexit ควรถูกเรียกในลำดับย้อนกลับเมื่อมีการเรียก exit หรือผลตอบแทนหลัก
Robert Gamble

เรียกใช้การทดสอบและดูเหมือนว่าตัวทำลายไปยังอินสแตนซ์ส่วนกลางจะถูกเรียกหลังจากทั้งหมดที่ออกจากการเรียกกลับ
strager

+1 เพื่อเตือนผู้คนว่าในที่สุดระบบปฏิบัติการจะทำให้ทรัพยากรที่จัดสรรทั้งหมดเป็นอิสระแม้ว่าจะมีการยกเลิกการโทร ()
Fingolfin

10

สิ่งต่อไปนี้เกิดขึ้นเมื่อโปรแกรมเรียกใช้exit():

  • ฟังก์ชันที่ลงทะเบียนโดยatexitฟังก์ชันจะดำเนินการ
  • สตรีมที่เปิดอยู่ทั้งหมดจะถูกล้างและปิดไฟล์ที่สร้างขึ้นtmpfileจะถูกลบออก
  • โปรแกรมจะสิ้นสุดด้วยรหัสทางออกที่ระบุไปยังโฮสต์

abort() ฟังก์ชันส่งSIGABRTสัญญาณไปยังกระบวนการปัจจุบันถ้ามันไม่ได้ถูกจับโปรแกรมจะสิ้นสุดลงด้วยการรับประกันว่าเปิดลำธารล้าง / ปิดหรือว่าไฟล์ชั่วคราวที่สร้างขึ้นผ่านtmpfileจะถูกลบออกatexitฟังก์ชั่นการลงทะเบียนจะไม่ได้เรียกว่าและไม่ใช่ สถานะการออกเป็นศูนย์จะถูกส่งกลับไปยังโฮสต์


อืมม มาตรฐานกล่าวว่าโปรแกรมจะไม่สิ้นสุดหากตัวจัดการสัญญาณ "ไม่กลับมา" เท่านั้น คุณค่อนข้างดีกับ C. คุณสามารถจินตนาการถึงสถานการณ์ใด ๆ ที่จะทำให้สามารถดำเนินการตามปกติต่อไปได้โดยไม่ต้องกลับมา? ฉันจินตนาการถึง longjmp แต่ฉันไม่แน่ใจว่ามันทำงานอย่างไรในตัวจัดการสัญญาณ
Johannes Schaub - litb

โดยทั่วไปการเรียก longjmp จากตัวจัดการสัญญาณไม่ได้กำหนดไว้ แต่มีกรณีพิเศษเมื่อสัญญาณถูกสร้างขึ้นด้วยการเพิ่ม / ยกเลิกดังนั้นฉันคิดว่านี่น่าจะเป็นไปได้ในทางทฤษฎีแม้ว่าฉันจะไม่คิดว่าฉันเคยเห็นมันทำ ตอนนี้ฉันจะต้องลองดู;)
Robert Gamble

1
ดูเหมือนว่าจะใช้งานได้ (แบ่งออกเป็นหลายโพสต์เนื่องจากขีด จำกัด 300 อักขระ): #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <setjmp.h> volatile sig_atomic_t do_abort = 1; jmp_buf env; เป็นโมฆะ abort_handler (int i) {do_abort = 0; longjmp (env, 1);}
Robert Gamble

int หลัก (โมฆะ) {setjmp (env); ทำให้ ("ที่ setjmp"); ถ้า (do_abort) {สัญญาณ (SIGABRT, abort_handler); ทำให้ ("โทรยกเลิก"); ยกเลิก (); } ทำให้ ("ไม่ได้แท้ง!"); กลับ 0; }
Robert Gamble

บน Ubuntu 7.04 สิ่งนี้พิมพ์: ที่ setjmp การโทรยกเลิกที่ setjmp ไม่ได้ยกเลิก!
Robert Gamble

5

จากหน้าคู่มือ exit ():

ฟังก์ชัน exit () ทำให้กระบวนการสิ้นสุดตามปกติและค่าสถานะ & 0377 จะถูกส่งกลับไปยังพาเรนต์

จากหน้าคู่มือการยกเลิก ():

ขั้นแรก abort () จะปลดบล็อกสัญญาณ SIGABRT จากนั้นเพิ่มสัญญาณดังกล่าวสำหรับกระบวนการโทร ส่งผลให้กระบวนการยุติผิดปกติเว้นแต่สัญญาณ SIGABRT ถูกจับได้และตัวจัดการสัญญาณไม่กลับมา


4

abortส่งSIGABRTสัญญาณ abortไม่กลับไปที่ผู้โทร ตัวจัดการเริ่มต้นสำหรับSIGABRTสัญญาณปิดแอปพลิเคชัน stdioสตรีมไฟล์จะล้างแล้วปิด อย่างไรก็ตามตัวทำลายสำหรับอินสแตนซ์คลาส C ++ นั้นไม่เป็นเช่นนั้น (ไม่แน่ใจในอันนี้ - ผลลัพธ์อาจไม่ได้กำหนด?)

exitมีการเรียกกลับของตัวเองตั้งค่าด้วยatexit. หากระบุการเรียกกลับ (หรือเพียงรายการเดียว) ระบบจะเรียกตามลำดับย้อนกลับของลำดับการลงทะเบียน (เช่นสแต็ก) จากนั้นโปรแกรมจะออก เช่นเดียวกับabort, exitไม่ได้กลับไปยังผู้โทร stdioสตรีมไฟล์จะล้างแล้วปิด นอกจากนี้ยังมีการเรียกตัวทำลายสำหรับอินสแตนซ์คลาส C ++


exit สามารถมีฟังก์ชันการโทรกลับหลายรายการที่ลงทะเบียนผ่าน atexit เมื่อ exit ถูกเรียกฟังก์ชันการโทรกลับทั้งหมดจะถูกเรียกตามลำดับย้อนกลับที่ลงทะเบียนไว้
Robert Gamble

@Gamble แน่นอนฉันพูดถึงตัวเองเมื่อไม่กี่นาทีที่ผ่านมาในความคิดเห็นต่อคำตอบของ @ Bondy ฉันจะแก้ไขคำตอบของตัวเองเพื่อสะท้อนสิ่งนั้น
strager
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.