Existe alguma diferença entre return n
(na main
função) e exit(n)
em C? É definido pelos padrões C ou POSIX ou depende do SO ou do compilador?
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 cleanup
funçã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_message
objeto 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 message
ponteiro global ) a um objeto alocado localmente main
e 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_EXIT
pode fazer nada, incluindo travar ou imprimir "hello, world"
(se a memória usada por local_message
nã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 argv
e por *argv
continuam 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 n
eexit
, seus comportamentos são como é definida em que a implementação.C99 define o comportamento do ambiente hospedado como,
fonte
Do ponto de vista do padrão C, não realmente, além de
return
ser uma declaração eexit()
uma função. Qualquer um deles fará com que quaisquer funções registradasatexit()
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 existentemain()
será renomeado para outra coisa e será chamado por um novomain()
.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 tratarmain()
como a função e usá-lareturn
quando quiser que ela termine.fonte