Na verdade, não é uma diferença, mas é sutil. Tem mais implicações para C ++, mas as diferenças são importantes.
Quando eu chamar return
em main()
, destruidores serão chamados para os meus objetos escopo localmente. Se eu ligar exit()
, nenhum destruidor será chamado para meus objetos com escopo local! Releia isso. exit()
não retorna . Isso significa que, assim que eu chamo, não há "backsies". Quaisquer objetos que você criou nessa função não serão destruídos. Frequentemente, isso não tem implicações, mas às vezes ocorre, como o fechamento de arquivos (certamente você deseja que todos os seus dados sejam descarregados para o disco?).
Observe que os static
objetos serão limpos mesmo se você ligar exit()
. Por fim, observe que se você usarabort()
, nenhum objeto será destruído. Ou seja, nenhum objeto global, nenhum objeto estático e nenhum objeto local terão seus destruidores chamados.
Prossiga com cuidado ao favorecer a saída em vez do retorno.
http://groups.google.com/group/gnu.gcc.help/msg/8348c50030cfd15a
thread_local
que os destruidores de objetos serão chamados. Destruidores para outros objetos locais ainda não são chamados. ideone.com/Y6Dh3fexit()
fechamento de arquivos de forma limpa está realmente errada. O único momento em que os dados podem não ser liberados é no caso oposto: ou seja, se um usareturn
frommain()
e um chamousetbuf()
ousetvbuf()
com um buffer declarado como armazenamento automático emmain()
(como discutido na resposta de R. abaixo). É uma pena que esta questão seja marcada com C e C ++ (e com estilo de codificação - não é um problema de estilo!).Outra diferença:
exit
é uma função da Biblioteca Padrão, portanto é necessário incluir cabeçalhos e vincular-se à biblioteca padrão. Para ilustrar (em C ++), este é um programa válido:mas para usar,
exit
você precisará incluir:Além disso, isso adiciona uma suposição adicional: a chamada
exit
demain
tem os mesmos efeitos colaterais do retorno zero. Como outros já apontaram, isso depende do tipo de executável que você está construindo (ou seja, quem está chamandomain
). Você está codificando um aplicativo que usa o C-runtime? Um plugin do Maya? Um serviço do Windows? Um motorista? Cada caso exigirá pesquisa para ver seexit
é equivalente areturn
. IMHO usandoexit
quando você realmente quer dizerreturn
apenas torna o código mais confuso. OTOH, se você realmente quer dizerexit
, então, por todos os meios, use-o.fonte
Há pelo menos uma razão para preferir
exit
: Se qualquer um dos seusatexit
manipuladores referem-se a dados de armazenamento de duração automática nomain
, ou se você usousetvbuf
ousetbuf
atribuir a um dos padrões córregos tampão em um de armazenamento de duração automáticamain
, em seguida, retornar demain
produz comportamento indefinido, mas a chamadaexit
é válida.Outro uso potencial (geralmente reservado para programas de brinquedo, no entanto) é sair de um programa com invocações recursivas de
main
.fonte
main()
- é apenas uma função como outra qualquer. Por outro lado, uma vez que tem menção especial no padrão, o padrão deve ser bastante cuidadoso sobre como definemain()
e as coisas próximas e queridas. No entanto, no final, embora o padrão não exija (e não deva ) exigir que os compiladores façam algo de especial no armazenamento automáticomain()
. Leia a nota de rodapé nº 11 abaixo do parágrafo que você referenciou em seu comentário.Eu sempre uso
return
porque o protótipo padrão paramain()
diz que ele retorna umint
.Dito isto, algumas versões dos padrões dão
main
tratamento especial e assumem que retornará 0 se não houver umareturn
declaração explícita . Dado o seguinte código:O G ++ gera apenas um aviso
foo()
e ignora o retorno ausente demain
:fonte
return
para finalizar sua execução. A chamadaexit()
também é uma maneira válida e, às vezes, necessária para finalizar a execução de qualquer função. De fato, como eu e outros descrevemos em outro lugar, chamarexit()
mesmomain()
transmite uma intenção muito mais clara de sair de todo o processo, preserva o armazenamento automático até a saída do processo e facilita a manutenção durante a refatoração futura do código. Para C, utilizandoreturn
emmain()
quando a intenção é a de terminar o processo é, assim, sem dúvida, uma má prática.Eu enfaticamente enfatizo o comentário de R. sobre o uso de exit () para evitar a
main()
recuperação automática do armazenamento antes que o programa realmente termine. Umareturn X;
declaração inmain()
não é precisamente equivalente a uma chamada paraexit(X);
, uma vez que o armazenamento dinâmico demain()
desaparece quandomain()
retorna, mas não desaparece se uma chamadaexit()
for feita.Além disso, em C ou em qualquer linguagem semelhante a C, uma
return
declaração sugere fortemente ao leitor que a execução continuará na função de chamada e, embora essa continuação de execução seja tecnicamente verdadeira, se você contar a rotina de inicialização C que chamou suamain()
função, não é exatamente o que você quer dizer quando pretende terminar o processo.Afinal, se você deseja finalizar seu programa a partir de qualquer outra função, exceto que
main()
você deve chamarexit()
. Fazer isso de forma consistentemain()
também torna seu código muito mais legível e também torna muito mais fácil para alguém re-fatorar seu código; ou seja, o código copiadomain()
para outra função não se comportará mal por causa dereturn
declarações acidentais que deveriam ter sidoexit()
chamadas.Portanto, combinando todos esses pontos, a conclusão é que é um mau hábito , pelo menos para C, usar uma
return
declaração para encerrar o programa emmain()
.fonte
exit()
em geral, mas use-o se athrow
ouabort()
alternativas não funcionarem em um contexto específico. Mas especialmente eviteexit()
em main e use o retorno em main como prática típica.Com alguns compiladores para plataformas incomuns,
exit()
pode converter seu argumento no valor de saída do seu programa enquanto um retorno demain()
apenas pode passar o valor diretamente para o ambiente host sem nenhuma tradução.O padrão requer um comportamento idêntico nesses casos (especificamente, ele diz que retornar algo que é
int
compatívelmain()
deve ser equivalente a chamarexit()
com esse valor). O problema é que sistemas operacionais diferentes têm convenções diferentes para interpretar os valores de saída. Em muitos sistemas (MUITOS!), 0 significa sucesso e qualquer outra coisa é um fracasso. Mas, digamos, VMS, valores ímpares significam sucesso e pares significam falha. Se você retornou 0 demain()
, um usuário do VMS receberia uma mensagem desagradável sobre uma violação de acesso. Na verdade, não houve uma violação de acesso - essa era simplesmente a mensagem padrão associada ao código de falha 0.Então o ANSI apareceu e abençoou
EXIT_SUCCESS
eEXIT_FAILURE
como argumentos você poderia passarexit()
. A norma também diz queexit(0)
deve comportar-se de forma idêntica paraexit(EXIT_SUCCESS)
, assim que a maioria das implementações definirEXIT_SUCCESS
a0
.O padrão, portanto, coloca você em um vínculo com o VMS, pois não deixa uma maneira padrão de retornar um código de falha que possua o valor 0.
O compilador VAX / VMS C da era do início dos anos 90, portanto, não interpretou o valor de retorno
main()
, simplesmente retornou qualquer valor ao ambiente host. Mas se você o utilizasseexit()
, faria o que o padrão exigia: converterEXIT_SUCCESS
(ou0
) em um código de sucesso eEXIT_FAILURE
em um código de falha genérico. Para usarEXIT_SUCCESS
, você tinha que passá-lo paraexit()
, você não poderia devolvê-lomain()
. Não sei se versões mais modernas desse compilador preservaram esse comportamento.Um programa C portátil costumava ficar assim:
Além: Se bem me lembro, a convenção VMS para valores de saída é mais diferenciada do que ímpar / par. Na verdade, ele usa algo como os três bits baixos para codificar um nível de gravidade. De um modo geral, no entanto, os níveis ímpares de gravidade indicavam sucesso ou informações diversas e os pares indicavam erros.
fonte
returned
demain
forma diferente do valor passado paraexit
- mas o padrão diz especificamente: "Se o tipo de retorno damain
função é um tipo compatível comint
, um retorno da chamada inicial para amain
função é equivalente a chamar aexit
função com o valor retornado pelamain
função como argumento ". Isso é C11; C89 / C90 tinha quase a mesma redação.EXIT_SUCCESS
, não havia como retornar um status de falha específico da plataforma com o valor 0, e pode ser por isso que alguns dos compiladores da época trataram o retorno do principal eexit()
diferente.Em C, retornar de
main
é exatamente o mesmo que chamarexit
com o mesmo valor.A seção 5.1.2.2.3 da norma C declara:
As regras para C ++ são um pouco diferentes, conforme mencionado em outras respostas.
fonte
Há realmente uma diferença entre
exit(0)
ereturn(0)
emmain
- quando a suamain
função é chamada várias vezes.O seguinte programa
Correr como
Resultará na seguinte saída:
No entanto, este:
Não imprimirá nada, independentemente dos argumentos.
Se você tem certeza de que ninguém nunca ligará para você
main
explicitamente, não é tecnicamente uma grande diferença em geral, mas manter um código mais claroexit
seria muito melhor. Se você, por algum motivo, quiser ligarmain
- você deve ajustá-lo às suas necessidades.Falando sobre C.
fonte