มีความแตกต่างระหว่าง return n และ exit (n) ใน C หรือไม่?


9

มีความแตกต่างระหว่างreturn n(ในmainฟังก์ชั่น) และexit(n)ใน C หรือไม่? มันถูกกำหนดโดยมาตรฐาน C หรือ POSIX หรือขึ้นอยู่กับระบบปฏิบัติการหรือคอมไพเลอร์?

คำตอบ:


5

ในกรณีส่วนใหญ่ไม่มีความแตกต่าง แต่นี่คือโปรแกรม C ที่มีแนวโน้มที่จะทำงานแตกต่างกันไปขึ้นอยู่กับว่ามันใช้return 0;หรือexit(0);:

#include <stdio.h>
#include <stdlib.h>

static char *message;

void cleanup(void) {
    printf("message = \"%s\"\n", message);
}

int main(void) {
    char local_message[] = "hello, world";
    message = local_message;
    atexit(cleanup);
#ifdef USE_EXIT
    puts("exit(0);");
    exit(0);
#else
    puts("return 0;");
    return 0;
#endif
}

เนื่องจากการatexit()เรียกใช้exit(0);หรือreturn 0;ทำให้cleanupฟังก์ชันถูกเรียกใช้ ความแตกต่างคือถ้าโปรแกรมเรียกexit(0);ใช้การล้างข้อมูลจะเกิดขึ้นในขณะที่ "เรียก" เพื่อmain()ยังคงทำงานอยู่ดังนั้นlocal_messageวัตถุยังคงมีอยู่ การดำเนินการreturn 0;แต่ทันทีที่ยุติการภาวนาของmain()และจากนั้นจะเรียกcleanup()ฟังก์ชั่น เนื่องจากการcleanup()อ้างอิง (ผ่านmessageตัวชี้โกลบอล) ไปยังวัตถุที่ถูกจัดสรรในmainเครื่องและไม่มีวัตถุนั้นอีกต่อไปพฤติกรรมจึงไม่ได้กำหนดไว้

นี่คือพฤติกรรมที่ฉันเห็นในระบบของฉัน:

$ gcc -DUSE_EXIT c.c -o c && ./c
exit(0);
message = "hello, world"
$ gcc c.c -o c && ./c
return 0;
message = ""
$ 

การรันโปรแกรมโดยไม่-DUSE_EXITสามารถทำอะไรได้รวมถึงการขัดข้องหรือการพิมพ์"hello, world"(หากหน่วยความจำที่ใช้โดยlocal_messageไม่เกิดการอุดตัน)

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


16
  • สำหรับ C
    The Standard บอกว่าการส่งคืนจากการโทรเริ่มต้นไปยัง main นั้นเทียบเท่ากับการโทรออก อย่างไรก็ตามการคืนค่าจากหลักไม่สามารถทำงานได้หากข้อมูลภายในเครื่องถึงหลักอาจจำเป็นในระหว่างการล้างข้อมูล

  • สำหรับ C ++

เมื่อใช้ exit (0) เพื่อออกจากโปรแกรมจะไม่มีการเรียก destructors สำหรับวัตถุที่ไม่มีการกำหนดขอบเขตแบบโลคัล แต่จะเรียกว่า destructors หากใช้ return 0

โปรแกรม 1 - - ใช้ exit (0) เพื่อออก

#include<iostream>
#include<stdio.h>
#include<stdlib.h>

using namespace std;

class Test {
public:
  Test() {
    printf("Inside Test's Constructor\n");
  }

  ~Test(){
    printf("Inside Test's Destructor");
    getchar();
  }
};

int main() {
  Test t1;

  // using exit(0) to exit from main
  exit(0);
}

ผลลัพธ์: ตัวสร้างการทดสอบภายใน

โปรแกรม 2 - ใช้ผลตอบแทน 0 เพื่อออก

#include<iostream>
#include<stdio.h>
#include<stdlib.h>

using namespace std;

class Test {
public:
  Test() {
    printf("Inside Test's Constructor\n");
  }

  ~Test(){
    printf("Inside Test's Destructor");
  }
};

int main() {
  Test t1;

   // using return 0 to exit from main
  return 0;
}

เอาท์พุท: สร้าง
การทดสอบภายในของ Destructor การทดสอบของ

บางครั้งการโทร destructors มีความสำคัญตัวอย่างเช่นถ้า destructor มีรหัสเพื่อปล่อยทรัพยากรเช่นไฟล์ปิด

โปรดทราบว่าวัตถุแบบคงที่จะถูกล้างออกแม้ว่าเราจะเรียก exit () ตัวอย่างเช่นดูโปรแกรมต่อไปนี้

#include<iostream>
#include<stdio.h>
#include<stdlib.h>

using namespace std;

class Test {
public:
  Test() {
    printf("Inside Test's Constructor\n");
  }

  ~Test(){
    printf("Inside Test's Destructor");
    getchar();
  }
};

int main() {
  static Test t1;  // Note that t1 is static

  exit(0);
}

เอาท์พุท: สร้าง
การทดสอบภายในของ Destructor การทดสอบของ


การปิดไฟล์ไม่ใช่ตัวอย่างที่ดีของตัวทำลายที่สำคัญที่จะเริ่มทำงานเมื่อคุณออกเนื่องจากไฟล์จะถูกปิดเมื่อออกจากโปรแกรม แต่อย่างใด
Winston Ewert

1
@WinstonEwert: จริง แต่อาจมีบัฟเฟอร์ระดับแอปพลิเคชันที่ยังคงต้องล้างข้อมูล
ฟิลิปป์

1
คำถามไม่ได้กล่าวถึง C ++ ที่ใดก็ได้ ...
tdammers

ฉันรู้ว่าไม่มีภาษาใดที่ให้อภัยฉัน แต่คำตอบนี้ทำให้ฉันคิดว่าทางออกเป็นเหมือนความล้มเหลวของ C # ดังนั้นใน C ++ จะออกในการลองใช้งานหรือไม่?
Jimmy Hoffa

@JimmyHoffa, c ++ ไม่มีfinally
Winston Ewert

6

คุ้มค่าสังเกตว่ามาตรฐาน C (C99) กำหนดสองประเภทของสภาพแวดล้อมการดำเนินการอิสระสิ่งแวดล้อมและHosted สิ่งแวดล้อม สภาพแวดล้อมอิสระคือสภาพแวดล้อม C ซึ่งไม่สนับสนุนไลบรารี C และมีไว้สำหรับแอปพลิเคชันแบบฝังและอื่น ๆ สภาพแวดล้อม AC ซึ่งสนับสนุนไลบรารี C เรียกว่าสภาพแวดล้อมแบบโฮสต์

C99 กล่าวว่าในการยกเลิกโปรแกรมสภาพแวดล้อมอิสระจะถูกกำหนดไว้ ดังนั้นถ้ากำหนดดำเนินการmain, return nและexitพฤติกรรมของพวกเขาจะเป็นที่ที่กำหนดไว้ในการใช้งานที่

C99 กำหนดพฤติกรรมสภาพแวดล้อมที่โฮสต์เป็น,

หากประเภทส่งคืนของฟังก์ชั่นหลักเป็นประเภทที่เข้ากันได้กับมันกลับมาจากการโทรเริ่มต้นไปยังฟังก์ชั่นหลักเทียบเท่ากับการเรียกฟังก์ชั่นออกที่มีค่าส่งกลับโดยฟังก์ชั่นหลักเป็นอาร์กิวเมนต์ ถึง} ที่ยุติฟังก์ชั่นหลักส่งคืนค่า 0 หากชนิดส่งคืนไม่เข้ากันกับ int สถานะการเลิกจ้างที่ส่งคืนไปยังสภาพแวดล้อมโฮสต์จะไม่ได้รับการระบุ


1
และมันก็ไม่สมเหตุสมผลเลยที่จะเรียก exit () จากสภาพแวดล้อมอิสระ สิ่งที่เทียบเท่ากับทางออก () จะเป็นการแขวนโปรแกรมในลูปนิรันดร์จากนั้นรอให้สุนัขเฝ้าบ้านหยุดพัก

0

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

มีสองสถานการณ์ที่คุณต้องระวัง:

  • main()สอบถามซ้ำใน ในขณะที่ไม่ค่อยได้เห็นในทางปฏิบัติมันเป็นเรื่องถูกกฎหมายใน C. (C ++ ห้ามอย่างชัดเจน)
  • การใช้main()ซ้ำ บางครั้งที่มีอยู่จะถูกเปลี่ยนชื่ออย่างอื่นและมีการเรียกใหม่main()main()

การใช้งานexit()จะเป็นการแนะนำบั๊กหากสิ่งใดสิ่งหนึ่งเกิดขึ้นหลังจากที่คุณได้เขียนรหัสโดยเฉพาะอย่างยิ่งหากไม่ยุติอย่างผิดปกติ เพื่อหลีกเลี่ยงปัญหาดังกล่าวจึงเป็นความคิดที่ดีที่คุณจะต้องปฏิบัติmain()ตามหน้าที่และการใช้งานreturnเมื่อคุณต้องการให้จบ

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