Có sự khác biệt nào giữa return n
(trong main
hàm) và exit(n)
trong C không? Được xác định bởi các tiêu chuẩn C hoặc POSIX hay nó phụ thuộc vào HĐH hoặc trình biên dịch?
Có sự khác biệt nào giữa return n
(trong main
hàm) và exit(n)
trong C không? Được xác định bởi các tiêu chuẩn C hoặc POSIX hay nó phụ thuộc vào HĐH hoặc trình biên dịch?
Câu trả lời:
Trong hầu hết các trường hợp, không có sự khác biệt, nhưng đây là chương trình C có khả năng hoạt động khác nhau tùy thuộc vào việc nó sử dụng return 0;
hay 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
}
Bởi vì các atexit()
cuộc gọi, một trong hai exit(0);
hoặc return 0;
nguyên nhân các cleanup
chức năng được gọi. Sự khác biệt là nếu chương trình gọi exit(0);
, việc dọn dẹp xảy ra trong khi "cuộc gọi" main()
vẫn còn hoạt động, vì vậy local_message
đối tượng vẫn tồn tại. Thực hiện return 0;
, tuy nhiên, ngay lập tức chấm dứt gọi trình main()
và sau đó gọi các cleanup()
chức năng. Vì tham chiếu cleanup()
(thông qua message
con trỏ toàn cục ) đến một đối tượng được phân bổ cục bộ main
và đối tượng đó không còn tồn tại, nên hành vi không được xác định.
Đây là hành vi tôi thấy trên hệ thống của mình:
$ gcc -DUSE_EXIT c.c -o c && ./c
exit(0);
message = "hello, world"
$ gcc c.c -o c && ./c
return 0;
message = ""
$
Chạy chương trình mà không -DUSE_EXIT
thể làm bất cứ điều gì, bao gồm cả sự cố hoặc in "hello, world"
(nếu bộ nhớ được sử dụng local_message
xảy ra không bị ghi đè).
Tuy nhiên, trong thực tế, sự khác biệt này chỉ hiển thị nếu các đối tượng được xác định cục bộ bên trong main()
được hiển thị bên ngoài main()
bằng cách lưu con trỏ vào chúng. Điều này có thể xảy ra hợp lý cho argv
. (Thử nghiệm trên hệ thống của tôi cho thấy các đối tượng được chỉ đến argv
và *argv
tiếp tục tồn tại sau khi trở về main()
, nhưng bạn không nên phụ thuộc vào điều đó.)
Đối với C
Tiêu chuẩn nói rằng việc trả lại từ cuộc gọi ban đầu đến chính tương đương với thoát lệnh gọi. Tuy nhiên, một sự trở lại từ chính không thể được dự kiến sẽ hoạt động nếu dữ liệu cục bộ đến chính có thể cần thiết trong quá trình dọn dẹp.
Dành cho C ++
Khi exit (0) được sử dụng để thoát khỏi chương trình, các hàm hủy cho các đối tượng không tĩnh trong phạm vi cục bộ không được gọi. Nhưng các hàm hủy được gọi nếu return 0 được sử dụng.
Chương trình 1 - - sử dụng exit (0) để thoát
#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);
}
Đầu ra: Inside Test's Con constructor
Chương trình 2 - sử dụng return 0 để thoát
#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;
}
Đầu ra: Inside Con's
Contortor Inside Test's Destructor
Gọi hàm hủy đôi khi rất quan trọng, ví dụ, nếu hàm hủy có mã để giải phóng tài nguyên như đóng tệp.
Lưu ý rằng các đối tượng tĩnh sẽ được dọn sạch ngay cả khi chúng ta gọi exit (). Ví dụ, xem chương trình sau đây.
#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);
}
Đầu ra: Inside Con's
Contortor Inside Test's Destructor
finally
Đáng chú ý là tiêu chuẩn C (C99) xác định hai loại môi trường thực thi là Môi trường tự do và Môi trường lưu trữ . Môi trường tự do là môi trường C không hỗ trợ các thư viện C và dành cho các ứng dụng nhúng và tương tự. Môi trường AC hỗ trợ các thư viện C được gọi là môi trường được lưu trữ.
C99 nói, trong một chấm dứt chương trình môi trường tự do được thực hiện được xác định. Vì vậy, nếu việc thực hiện định nghĩa main
, return n
và exit
, hành vi của họ được xác định như trong việc thực hiện đó.
C99 định nghĩa hành vi môi trường được lưu trữ là,
Nếu kiểu trả về của hàm chính là một loại tương thích với nó, thì việc trả về từ lệnh gọi ban đầu đến hàm chính tương đương với việc gọi hàm thoát với giá trị được trả về bởi hàm chính làm đối số của nó; đạt đến} kết thúc hàm chính trả về giá trị 0. Nếu kiểu trả về không tương thích với int, trạng thái kết thúc được trả về môi trường máy chủ là không xác định.
Từ quan điểm của tiêu chuẩn C, không thực sự, ngoài return
việc là một tuyên bố và exit()
là một chức năng. Hoặc sẽ gây ra bất kỳ chức năng nào được đăng ký atexit()
để được gọi theo sau là chấm dứt chương trình.
Có một vài tình huống bạn muốn đề phòng:
main()
. Mặc dù hiếm khi được nhìn thấy trong thực tế, nó là hợp pháp trong C. (C ++ rõ ràng cấm nó.)main()
. Đôi khi một cái hiện có main()
sẽ được đổi tên thành cái khác và được gọi bởi một cái mới main()
.Việc sử dụng exit()
sẽ gây ra lỗi nếu một trong hai lỗi xảy ra sau khi bạn đã viết mã, đặc biệt là nếu không chấm dứt bất thường. Để tránh điều đó, bạn nên tập thói quen coi main()
chức năng của nó và sử dụng return
khi bạn muốn nó kết thúc.