return statement vs exit () em main ()

Devo usar exit() ou apenas return instruções em main() ? Pessoalmente eu sou a favor das declarações de return porque eu sinto que é como ler qualquer outra function e o controle de stream quando eu estou lendo o código é bom (na minha opinião). E mesmo se eu quiser refatorar a function main() , ter return parece uma escolha melhor do que exit() .

O exit() faz algo especial que o return não faz?

   

    Na verdade, há uma diferença, mas é sutil. Isso tem mais implicações para o C ++, mas as diferenças são importantes.

    Quando eu chamo de return em main() , os destruidores serão chamados para meus objects de escopo local. Se eu chamar exit() , nenhum destruidor será chamado para meus objects de escopo local! Releia isso. exit() não retorna . Isso significa que uma vez que eu chamo, não há “backsies”. Todos os objects que você criou nessa function não serão destruídos. Muitas vezes isso não tem implicações, mas às vezes acontece, como fechar arquivos (com certeza você quer que todos os seus dados sejam liberados para o disco?).

    Note que objects static serão limpos mesmo se você chamar exit() . Finalmente, observe que, se você usar abort() , nenhum object será destruído. Ou seja, nenhum object global, nenhum object estático e nenhum object local terá seus destrutores chamados.

    Prossiga com caucanvas ao favorecer a saída sobre o retorno.

    http://groups.google.com/group/gnu.gcc.help/msg/8348c50030cfd15a

    Outra diferença: a exit é uma function da biblioteca padrão, portanto, é necessário include headers e vincular à biblioteca padrão. Para ilustrar (em C ++), este é um programa válido:

     int main() { return 0; } 

    mas para usar exit você precisa de um include:

     #include  int main() { exit(EXIT_SUCCESS); } 

    Além disso, isso adiciona uma suposição adicional: a exit chamada main tem os mesmos efeitos colaterais que retornar zero. Como outros apontaram, isso depende do tipo de executável que você está criando (ou seja, quem está chamando de main ). Você está codificando um aplicativo que usa o tempo de execução C? Um plugin do Maya? Um serviço do Windows? Um motorista? Cada caso exigirá pesquisa para ver se a exit é equivalente a return . IMHO usando exit quando você realmente quer dizer return apenas torna o código mais confuso. OTOH, se você realmente quer dizer exit , então, por todos os meios, use-o.

    Há pelo menos uma razão para preferir exit : Se algum dos seus manipuladores atexit referir a dados de duração de armazenamento automático no main , ou se você usou setvbuf ou setbuf para atribuir a um dos streams padrão um buffer de duração de armazenamento automático main , retornando de main produz comportamento indefinido, mas a exit chamada é válida.

    Outro uso potencial (geralmente reservado para programas de brinquedos, no entanto) é sair de um programa com invocações recursivas de main .

    Eu sempre uso return porque o protótipo padrão para main() diz que ele retorna um int .

    Dito isso, algumas versões dos padrões dão um tratamento especial main e assumem que ele retorna 0 se não houver uma instrução de return explícita. Dado o seguinte código:

     int foo() {} int main(int argc, char *argv[]) {} 

    G ++ apenas gera um aviso para foo() e ignora o retorno ausente do main :

     % g++ -Wall -c foo.cc foo.cc: In function 'int foo()': foo.cc:1: warning: control reaches end of non-void function 

    Eu recomendo o comentário feito por R. sobre o uso de exit () para evitar que o armazenamento automático em main() recuperado antes que o programa realmente termine. Um return X; declaração em main() não é precisamente equivalente a uma chamada para exit(X); , uma vez que o armazenamento dynamic de main() desaparece quando main() retorna, mas ele não desaparece se uma chamada para exit() for feita no lugar.

    Além disso, em C ou em qualquer linguagem semelhante a C, uma instrução de return sugere fortemente ao leitor que a execução continuará na function de chamada, e embora essa continuação da execução seja tecnicamente verdadeira se você contar a rotina de boot C chamada main() function, não é exatamente o que você quer dizer quando quer terminar o processo.

    Afinal, se você quiser terminar seu programa de dentro de qualquer outra function, exceto main() você deve chamar exit() . Fazê-lo consistentemente em main() também torna o seu código muito mais legível, e também torna muito mais fácil para qualquer um re-fatorar seu código; Ou seja, o código copiado de main() para alguma outra function não se comportará mal por causa de declarações de return acidental que deveriam ter sido chamadas de exit() .

    Então, combinando todos esses pontos juntos, a conclusão é que é um mau hábito , pelo menos para C, usar uma instrução de return para finalizar o programa em main() .

    O exit () faz algo especial que ‘return’ não faz?

    Com alguns compiladores para plataformas incomuns, exit() pode traduzir seu argumento no valor de saída do seu programa enquanto um retorno de main() pode apenas passar o valor diretamente para o ambiente host sem nenhuma tradução.

    O padrão requer comportamento idêntico nesses casos (especificamente, diz que retornar algo que seja int -compatível de main() deve ser equivalente a chamar exit() com esse valor). O problema é que diferentes SOs possuem diferentes convenções para interpretar os valores de saída. Em muitos sistemas (MANY!), 0 significa sucesso e qualquer outra coisa é uma falha. Mas, digamos, no VMS, valores ímpares significam sucesso e até mesmo significam falha. Se você retornou 0 de main() , um usuário do VMS veria uma mensagem desagradável sobre uma violação de access. Na verdade, não havia uma violação de access – essa era simplesmente a mensagem padrão associada ao código de falha 0.

    Então ANSI apareceu e abençoou EXIT_SUCCESS e EXIT_FAILURE como argumentos que você poderia passar para exit() . O padrão também diz que exit(0) deve se comportar de maneira idêntica para exit(EXIT_SUCCESS) , portanto, a maioria das implementações define EXIT_SUCCESS como 0 .

    O padrão, portanto, coloca você em um vínculo no VMS, pois não deixa um caminho padrão para retornar um código de falha que tenha o valor 0.

    O compilador VAX / VMS C do início dos anos 1990, portanto, não interpretou o valor de retorno de main() , ele simplesmente retornou qualquer valor para o ambiente do host. Mas se você usou exit() ele faria o que o padrão requerido: traduzir EXIT_SUCCESS (ou 0 ) em um código de sucesso e EXIT_FAILURE em um código de falha genérico. Para usar o EXIT_SUCCESS , você tinha que passá-lo para exit() , você não poderia retorná-lo do main() . Não sei se versões mais modernas desse compilador preservaram esse comportamento.

    Um programa C portátil costumava ficar assim:

     #include  #include  int main() { printf("Hello, World!\n"); exit(EXIT_SUCCESS); /* to get good return value to OS */ /*NOTREACHED*/ /* to silence lint warning */ return 0; /* to silence compiler warning */ } 

    Aparte: Se bem me lembro, a convenção VMS para valores de saída é mais sutil que ímpar / par. Ele realmente usa algo como os três bits baixos para codificar um nível de gravidade. De um modo geral, no entanto, os níveis de severidade ímpares indicavam sucesso ou informações diversas e os pares indicavam erros.