Existe alguma diferença entre return n(na mainfunção) e exit(n)em C? É definido pelos padrões C ou POSIX ou depende do SO ou do compilador?
Existe alguma diferença entre return n(na mainfunção) e exit(n)em C? É definido pelos padrões C ou POSIX ou depende do SO ou do compilador?
Respostas:
Na maioria dos casos, não há diferença, mas aqui está um programa em C que provavelmente se comportará de maneira diferente dependendo de usar return 0;ou 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
}
Por causa da atexit()chamada, exit(0);ou return 0;faz com que a cleanupfunção seja chamada. A diferença é que, se o programa chama exit(0);, a limpeza acontece enquanto a "chamada" main()ainda está ativa, portanto o local_messageobjeto ainda existe. A execução return 0;, no entanto, termina imediatamente a chamada main()e depois chama a cleanup()função. Como cleanup()se refere (por meio do messageponteiro global ) a um objeto alocado localmente maine esse objeto não existe mais, o comportamento é indefinido.
Aqui está o comportamento que vejo no meu sistema:
$ gcc -DUSE_EXIT c.c -o c && ./c
exit(0);
message = "hello, world"
$ gcc c.c -o c && ./c
return 0;
message = ""
$
A execução do programa sem -DUSE_EXITpode fazer nada, incluindo travar ou imprimir "hello, world"(se a memória usada por local_messagenão for derrotada).
Na prática, porém, essa diferença só aparece se os objetos definidos localmente dentro main()são tornados visíveis fora main(), salvando ponteiros para eles. Isso poderia acontecer plausivelmente argv. (A experiência no meu sistema mostra que os objetos apontados por argve por *argvcontinuam existindo após o retorno main(), mas você não deve depender disso.)
Para C
O Standard diz que um retorno da chamada inicial para a principal é equivalente a chamar exit. No entanto, não se espera que um retorno do main funcione se forem necessários dados locais para o main durante a limpeza.
Para C ++
Quando exit (0) é usado para sair do programa, os destruidores de objetos não estáticos com escopo local não são chamados. Mas os destruidores são chamados se o retorno 0 for usado.
Programa 1 - - usa exit (0) para sair
#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);
}
Saída: Construtor do Teste Interno
Programa 2 - usa o retorno 0 para sair
#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;
}
Saída: Construtor do
Inside Test Destrutor do Inside Test
Chamar destruidores às vezes é importante, por exemplo, se o destruidor tiver código para liberar recursos, como fechar arquivos.
Observe que os objetos estáticos serão limpos mesmo se chamarmos exit (). Por exemplo, consulte o programa a seguir.
#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);
}
Saída: Construtor do
Inside Test Destrutor do Inside Test
finally
Vale ressaltar que o padrão C (C99) define dois tipos de ambientes de execução, Ambiente Independente e Ambiente Hospedado . O ambiente independente é um ambiente C que não suporta as bibliotecas C e destina-se a aplicativos incorporados e similares. O ambiente de CA que suporta as bibliotecas C é chamado de ambiente hospedado.
C99 diz que, em um ambiente independente, a finalização do programa é definida como implementação. Então, se os define de implementação main, return ne exit, seus comportamentos são como é definida em que a implementação.
C99 define o comportamento do ambiente hospedado como,
Se o tipo de retorno da função principal for compatível, um retorno da chamada inicial para a função principal será equivalente a chamar a função de saída com o valor retornado pela função principal como argumento; atingir o} que finaliza a função principal retorna um valor 0. Se o tipo de retorno não for compatível com int, o status de finalização retornado ao ambiente host não será especificado.
Do ponto de vista do padrão C, não realmente, além de returnser uma declaração e exit()uma função. Qualquer um deles fará com que quaisquer funções registradas atexit()sejam chamadas, seguidas pelo término do programa.
Há algumas situações que você deseja observar:
main(). Embora raramente seja visto na prática, é legal em C. (o C ++ proíbe explicitamente).main(). Às vezes, um existente main()será renomeado para outra coisa e será chamado por um novo main().O uso de exit()introduzirá um bug se um desses acontecer depois que você escrever o código, especialmente se não terminar de forma anormal. Para evitar isso, é uma boa idéia ter o hábito de tratar main()como a função e usá-la returnquando quiser que ela termine.