Qual é a maneira correta (mais eficiente) de definir a main()
função em C e C ++ - int main()
ou void main()
- e por quê? Se int main()
então return 1
ou return 0
?
Existem inúmeras duplicatas dessa pergunta, incluindo:
- Quais são as assinaturas válidas para a
main()
função C ? - O tipo de retorno da
main()
função - Diferença entre
void main()
eint main()
? main()
assinatura em C ++- Qual é a declaração adequada de
main()
? - Para C ++, com uma resposta muito boa mesmo. - Estilos de
main()
funções em C - Retornar tipo de
main()
método em C int main()
vsvoid main()
em C
Relacionado:
- C ++ -
int main(int argc, char **argv)
- C ++ -
int main(int argc, char *argv[])
- É
char *envp[]
como um terceiro argumento paramain()
portátil? - A
int main()
função deve retornar um valor em todos os compiladores? - Por que o tipo de
main()
função em C e C ++ é deixado para o usuário definir? - Por que
int main(){}
compilar? - Definições legais de
main()
em C ++ 14?
c++
c
return-value
main
return-type
Joel
fonte
fonte
main
é chamado uma vez (e em C ++ pode ser chamado apenas uma vez: sem recursão). Se você não deseja que a execução gaste muito tempomain
, não invoque o programa várias vezes: faça com que o programa implemente a repetição.#include
declaraçõesreturn
emmain(...)
um dispositivo incorporado, seu sistema entrará em um estado imprevisível e sua lavadora de roupas se tornará autoconsciente e tentará matá-lo. Então, nós usamosvoid main()
nesse caso. Essa é uma prática padrão do setor em embarcações bare-metal.Respostas:
O valor de retorno para
main
indica como o programa foi encerrado. A saída normal é representada por um valor de retorno 0 demain
. A saída anormal é sinalizada por um retorno diferente de zero, mas não existe um padrão para a interpretação dos códigos diferentes de zero. Conforme observado por outros,void main()
é proibido pelo padrão C ++ e não deve ser usado. Asmain
assinaturas válidas do C ++ são:e
que é equivalente a
Também é importante notar que, em C ++,
int main()
pode ser deixado sem uma declaração de retorno; nesse momento, o padrão é retornar 0. Isso também ocorre com um programa C99. Sereturn 0;
deve ser omitido ou não, está aberto ao debate. O intervalo de assinaturas principais válidas do programa C é muito maior.Eficiência não é um problema com a
main
função. Só pode ser inserido e deixado uma vez (marcando o início e o término do programa) de acordo com o padrão C ++. Para C, a reinserçãomain()
é permitida, mas deve ser evitada.fonte
A resposta aceita parece ser direcionada para C ++, então pensei em adicionar uma resposta que pertença a C, e isso difere de algumas maneiras.
ISO / IEC 9899: 1989 (C90):
main()
deve ser declarado como:Ou equivalente. Por exemplo,
int main(int argc, char *argv[])
é equivalente ao segundo. Além disso, oint
tipo de retorno pode ser omitido, pois é o padrão.Se uma implementação permitir,
main()
pode ser declarada de outras maneiras, mas isso torna a implementação do programa definida e não está mais em conformidade estrita.O padrão define 3 valores para retorno que estão estritamente em conformidade (ou seja, não se baseiam no comportamento definido pela implementação):
0
eEXIT_SUCCESS
para uma finalização bem-sucedida eEXIT_FAILURE
para uma finalização malsucedida. Quaisquer outros valores não são padrão e a implementação é definida.main()
deve ter umareturn
declaração explícita no final para evitar comportamento indefinido.Finalmente, não há nada errado do ponto de vista dos padrões com a chamada
main()
de um programa.ISO / IEC 9899: 1999 (C99):
Para C99, tudo é o mesmo que acima, exceto:
int
tipo de retorno não pode ser omitido.main()
. Se você faz, emain()
terminou, há um implícitoreturn 0
.fonte
Padrão C - Ambiente Hospedado
Para um ambiente hospedado (esse é o normal), o padrão C11 (ISO / IEC 9899: 2011) diz:
Encerramento do programa em C99 ou C11
O valor retornado
main()
é transmitido para o 'ambiente' de uma maneira definida pela implementação.Observe que
0
é obrigatório como 'sucesso'. Você pode usarEXIT_FAILURE
eEXIT_SUCCESS
de,<stdlib.h>
se preferir, mas 0 está bem estabelecido e 1. também. Consulte também Códigos de saída maiores que 255 - possíveis? .No C89 (e, portanto, no Microsoft C), não há nenhuma declaração sobre o que acontece se a
main()
função retornar, mas não especificar um valor de retorno; portanto, leva a um comportamento indefinido.C ++ padrão - ambiente hospedado
O padrão C ++ 11 (ISO / IEC 14882: 2011) diz:
O padrão C ++ diz explicitamente "Ele [a função principal] deve ter um tipo de retorno do tipo
int
, mas, caso contrário, seu tipo é definido pela implementação" e requer as mesmas duas assinaturas que o padrão C para ser suportado como opções. Portanto, um 'void main ()' não é diretamente permitido pelo padrão C ++, embora não haja nada que possa ser feito para interromper uma implementação fora do padrão que permita alternativas. Observe que o C ++ proíbe o usuário de chamarmain
(mas o padrão C não).Há um parágrafo de §18.5 Início e término no padrão C ++ 11 que é idêntico ao parágrafo de §7.22.4.4 A
exit
função no padrão C11 (citado acima), além de uma nota de rodapé (que simplesmente documentaEXIT_SUCCESS
eEXIT_FAILURE
está definida in<cstdlib>
).Padrão C - Extensão comum
Classicamente, os sistemas Unix suportam uma terceira variante:
O terceiro argumento é uma lista terminada em nulo de ponteiros para seqüências de caracteres, cada um dos quais é uma variável de ambiente que possui um nome, um sinal de igual e um valor (possivelmente vazio). Se você não usar isso, ainda poderá acessar o ambiente via '
extern char **environ;
'. Essa variável global é única entre as do POSIX, pois não possui um cabeçalho que a declare.Isso é reconhecido pela norma C como uma extensão comum, documentada no anexo J:
Microsoft C
O compilador do Microsoft VS 2010 é interessante. O site diz:
Não está claro para mim o que acontece (qual código de saída é retornado ao pai ou SO) quando um programa
void main()
sai - e o site da MS também fica silencioso.Curiosamente, a MS não prescreve a versão de dois argumentos
main()
exigida pelos padrões C e C ++. Apenas prescreve uma forma de três argumentos em que o terceiro argumento échar **envp
um ponteiro para uma lista de variáveis de ambiente.A página da Microsoft também lista algumas outras alternativas -
wmain()
que exigem amplas cadeias de caracteres e muito mais.A versão do Microsoft Visual Studio 2005 desta página não lista
void main()
como alternativa. As versões do Microsoft Visual Studio 2008 em diante.Padrão C - Ambiente Independente
Como observado anteriormente, os requisitos acima se aplicam aos ambientes hospedados. Se você estiver trabalhando com um ambiente independente (que é a alternativa a um ambiente hospedado), o padrão terá muito menos a dizer. Para um ambiente independente, a função chamada na inicialização do programa não precisa ser chamada
main
e não há restrições em seu tipo de retorno. O padrão diz:A referência cruzada à cláusula 4 Conformidade refere-se a isso:
É perceptível que o único cabeçalho necessário para um ambiente independente que realmente define quaisquer funções é
<stdarg.h>
(e mesmo essas podem ser - e geralmente são - apenas macros).C ++ padrão - ambiente independente
Assim como o padrão C reconhece o ambiente hospedado e independente, o mesmo ocorre com o padrão C ++. (Cotações da ISO / IEC 14882: 2011.)
Que tal usar
int main()
em C?O padrão §5.1.2.2.1 do padrão C11 mostra a notação preferida -
int main(void)
- mas também existem dois exemplos no padrão que mostramint main()
: §6.5.3.4 ¶8 e §6.7.6.3 ¶20 . Agora, é importante notar que os exemplos não são 'normativos'; eles são apenas ilustrativos. Se houver erros nos exemplos, eles não afetam diretamente o texto principal do padrão. Dito isto, eles são fortemente indicativos do comportamento esperado; portanto, se o padrão incluirint main()
um exemplo, isso sugere queint main()
não é proibido, mesmo que não seja a notação preferida.fonte
int main(){ … }
especifica que a função não aceita argumentos, mas não fornece um protótipo de função, AFAICT. Poismain()
isso raramente é um problema; significa que, se você tiver chamadas recursivasmain()
, os argumentos não serão verificados. Para outras funções, é mais um problema - você realmente precisa de um protótipo no escopo quando a função é chamada para garantir que os argumentos estejam corretos.main()
recursiva, fora de lugares como o IOCCC. Eu tenho um programa de teste que faz isso - principalmente para novidades. Se você temint i = 0; int main() { if (i++ < 10) main(i, i * i); return 0; }
e compila com o GCC e não o inclui-Wstrict-prototypes
, ele é compilado corretamente sob avisos rigorosos. Se formain(void)
, não consegue compilar.Eu acredito que
main()
deve retornarEXIT_SUCCESS
ouEXIT_FAILURE
. Eles são definidos emstdlib.h
fonte
EXIT_SUCCESS
eEXIT_FAILURE
porque alguns sistemas operacionais históricos (VMS?) Usaram um número diferente de 0 para indicar sucesso. Hoje é 0 em todos os lugares.exit(EXIT_SUCCESS)
, o que sempre fazia a coisa certa.Observe que os padrões C e C ++ definem dois tipos de implementações: autônomo e hospedado.
Ambiente hospedado C90
Formulários permitidos 1 :
Comentários:
Os dois primeiros são explicitamente declarados como os formulários permitidos, os outros são implicitamente permitidos porque o C90 permitiu "int implícito" para os parâmetros de tipo e função de retorno. Nenhum outro formulário é permitido.
Ambiente independente C90
Qualquer forma ou nome de main é permitido 2 .
Ambiente hospedado C99
Formulários permitidos 3 :
Comentários:
O C99 removeu "int implícito" e, portanto,
main()
não é mais válido.Uma frase estranha e ambígua "ou de alguma outra maneira definida pela implementação" foi introduzida. Isso pode ser interpretado como "os parâmetros para
int main()
variar" ou "principal pode ter qualquer forma definida pela implementação".Alguns compiladores optaram por interpretar o padrão da última maneira. Indiscutivelmente, não se pode afirmar facilmente que eles não estão em conformidade estrita citando o padrão em si, pois é ambíguo.
No entanto, permitir formas completamente selvagens de
main()
provavelmente não era (?) A intenção dessa nova frase. A lógica C99 (não normativa) implica que a sentença se refere a parâmetros adicionais paraint main
4 .No entanto, a seção para encerramento do programa do ambiente hospedado continua discutindo sobre o caso em que main não retorna int 5 . Embora essa seção não seja normativa sobre como main deve ser declarado, ela definitivamente implica que main pode ser declarado de uma maneira completamente definida pela implementação, mesmo em sistemas hospedados.
Ambiente independente C99
Qualquer forma ou nome de main é permitido 6 .
Ambiente hospedado C11
Formulários permitidos 7 :
Ambiente independente C11
Qualquer forma ou nome de main é permitido 8 .
Observe que
int main()
nunca foi listado como um formulário válido para qualquer implementação hospedada de C em qualquer uma das versões acima. Em C, diferente de C ++,()
e(void)
tem significados diferentes. O primeiro é um recurso obsoleto que pode ser removido do idioma. Consulte as instruções futuras sobre o idioma C11:Ambiente hospedado em C ++ 03
Formulários permitidos 9 :
Comentários:
Observe o parêntese vazio no primeiro formulário. C ++ e C são diferentes nesse caso, porque em C ++ isso significa que a função não aceita parâmetros. Mas em C, isso significa que pode levar qualquer parâmetro.
Ambiente independente C ++ 03
O nome da função chamada na inicialização é definido pela implementação. Se for nomeado
main()
, deve seguir os formulários 10 :Ambiente hospedado em C ++ 11
Formulários permitidos 11 :
Comentários:
O texto do padrão foi alterado, mas tem o mesmo significado.
Ambiente independente C ++ 11
O nome da função chamada na inicialização é definido pela implementação. Se for nomeado
main()
, deve seguir os formulários declarados 12 :Referências
ANSI X3.159-1989 2.1.2.2 Ambiente hospedado. "Inicialização do programa"
ANSI X3.159-1989 2.1.2.1 Ambiente independente:
ISO 9899: 1999 5.1.2.2 Ambiente hospedado -> 5.1.2.2.1 Inicialização do programa
Fundamentação da Norma Internacional - Linguagens de Programação - C, Revisão 5.10. 5.1.2.2 Ambiente hospedado -> 5.1.2.2.1 Inicialização do programa
ISO 9899: 1999 5.1.2.2 Ambiente hospedado -> 5.1.2.2.3 Finalização do programa
ISO 9899: 1999 5.1.2.1 Ambiente independente
ISO 9899: 2011 5.1.2.2 Ambiente hospedado -> 5.1.2.2.1 Inicialização do programa
Esta seção é idêntica à C99 citada acima.
ISO 9899: 1999 5.1.2.1 Ambiente independente
Esta seção é idêntica à C99 citada acima.
ISO 14882: 2003 3.6.1 Função principal
ISO 14882: 2003 3.6.1 Função principal
ISO 14882: 2011 3.6.1 Função principal
ISO 14882: 2011 3.6.1 Função principal
Esta seção é idêntica à C ++ 03 citada acima.
fonte
int my_startup_function ()
ou,int my_startup_function (int argc, char *argv[])
mas pode ter, por exemplo:char my_startup_function (long argc, int *argv[])
também uma função de inicialização? Eu acho que não, certo? Além disso, isso não é ambíguo também?main()
porque deve usar uma das assinaturas listadas. Eu imaginaria o esmagadoramente mais comumvoid my_startup_function ()
, pois não faz sentido retornar do programa em sistemas independentes.main
? Desculpe se essa não é uma pergunta inteligente, mas eu não conseguia entender o raciocínio por trás.func()
seja considerado obsoleto, o próprio rascunho usaint main()
em seus próprios exemplos.Retorne 0 em caso de sucesso e diferente de zero por erro. Esse é o padrão usado pelos scripts UNIX e DOS para descobrir o que aconteceu com o seu programa.
fonte
main()
nos tipos de retorno não especificados em C89 e K&R C, o padrão é 'int'.Se você não escrever uma declaração de retorno
int main()
, o fechamento{
retornará 0 por padrão.return 0
oureturn 1
será recebido pelo processo pai. Em um shell, ele entra em uma variável do shell e, se você estiver executando seu programa, forme um shell e não a utilize, não precisará se preocupar com o valor de retorno demain()
.Consulte Como posso obter o que minha função principal retornou? .
Dessa forma, você pode ver que é a variável
$?
que recebe o byte menos significativo do valor de retorno demain()
.Nos scripts Unix e DOS,
return 0
em caso de sucesso e diferente de zero para erro, geralmente são retornados. Este é o padrão usado pelos scripts Unix e DOS para descobrir o que aconteceu com o seu programa e controlar todo o fluxo.fonte
$?
não é uma variável de ambiente; é uma variável predefinida (ou incorporada) do shell. A diferença é difícil de detectar, mas se você executarenv
(sem argumentos), ele imprime o ambiente e$?
não será mostrado no ambiente.{
" deve ser}
. O SO não permitirá que eu faça uma edição tão pequena.Lembre-se de que, mesmo retornando um int, alguns sistemas operacionais (Windows) truncam o valor retornado para um único byte (0-255).
fonte
unsigned
). É o mesmo em sistemas UNIX com números inteiros de 32 bits. Mas as conchas no estilo UNIX em ambos os sistemas normalmente retêm apenas um número inteiro de 8 bits não assinado.O valor de retorno pode ser usado pelo sistema operacional para verificar como o programa foi fechado.
O valor de retorno 0 geralmente significa OK na maioria dos sistemas operacionais (os que eu consigo pensar de qualquer maneira).
Também pode ser verificado quando você chama um processo por conta própria e vê se o programa foi encerrado e finalizado corretamente.
NÃO é apenas uma convenção de programação.
fonte
O valor de retorno
main()
mostra como o programa foi encerrado. Se o valor de retorno forzero
, significa que a execução foi bem-sucedida, enquanto qualquer valor diferente de zero representará que algo deu errado na execução.fonte
Fiquei com a impressão de que o padrão especifica que main não precisa de um valor de retorno, pois um retorno bem-sucedido foi baseado no SO (zero em um pode ser um sucesso ou uma falha em outro); portanto, a ausência de retorno foi uma sugestão para o compilador para inserir o retorno bem-sucedido.
No entanto, geralmente retorno 0.
fonte
Retornar 0 deve informar ao programador que o programa concluiu o trabalho com êxito.
fonte
main()
normalmente sinaliza que ocorreu um erro; retornando 0 sinais de sucesso. Se seus programas sempre falharem, 1 está OK, mas não é a melhor idéia.1
demain
é definido pela implementação. Os valores só definiu-idioma são0
,EXIT_SUCCESS
(muitas vezes definido como0
), eEXIT_FAILURE
. No OpenVMS,return 1;
denota finalização bem-sucedida .Omitir
return 0
Quando um programa C ou C ++ chega ao final do
main
compilador, o código é gerado automaticamente para retornar 0, portanto, não há necessidade de colocarreturn 0;
explicitamente no final demain
.Nota: quando faço essa sugestão, é quase invariavelmente seguida por um dos dois tipos de comentários: "Eu não sabia disso". ou "Isso é um mau conselho!" Minha lógica é que é seguro e útil confiar no comportamento do compilador explicitamente suportado pelo padrão. Para C, desde C99; veja ISO / IEC 9899: 1999, seção 5.1.2.2.3:
Para C ++, desde o primeiro padrão em 1998; veja ISO / IEC 14882: 1998, seção 3.6.1:
Todas as versões dos dois padrões desde então (C99 e C ++ 98) mantiveram a mesma idéia. Contamos com funções-membro geradas automaticamente em C ++, e poucas pessoas escrevem
return;
instruções explícitas no final de umavoid
função. Razões contra a omissão parecem resumir-se a "parece estranho" . Se, como eu, você estiver curioso sobre a justificativa para a mudança no padrão C, leia esta pergunta . Observe também que, no início dos anos 90, isso era considerado "prática descuidada" porque era um comportamento indefinido (embora amplamente aceito) na época.Além disso, as Diretrizes Principais do C ++ contêm várias instâncias de omissão
return 0;
no finalmain
e nenhuma instância na qual um retorno explícito é gravado. Embora ainda não exista uma diretriz específica sobre esse tópico específico nesse documento, isso parece pelo menos um endosso tácito da prática.Então, eu advogo a omissão; outros discordam (muitas vezes veementemente!) De qualquer forma, se você encontrar um código que o omita, saberá que ele é explicitamente suportado pelo padrão e saberá o que isso significa.
fonte
return 0;
, no entanto, eu observaria que muitos compiladores daquela época também implementaram um implícitoreturn 0;
antes mesmo de padronizado.return 0
há mais de uma década. Também as versões atuais do Microsoft C também são compatíveis . Talvez sua informação esteja desatualizada?O que retornar depende do que você deseja fazer com o executável. Por exemplo, se você estiver usando seu programa com um shell de linha de comando, será necessário retornar 0 para um sucesso e um zero para falha. Você poderá usar o programa em shells com processamento condicional, dependendo do resultado do seu código. Além disso, você pode atribuir qualquer valor diferente de zero de acordo com sua interpretação, por exemplo, para erros críticos, diferentes pontos de saída do programa podem encerrar um programa com diferentes valores de saída e que está disponível para o shell de chamada que pode decidir o que fazer inspecionando o valor retornado. Se o código não se destina ao uso com shells e o valor retornado não incomoda ninguém, ele pode ser omitido. Eu pessoalmente uso a assinatura
int main (void) { .. return 0; .. }
fonte
main
é compatívelint
. Portanto, retornarint
não será um problema. Embora outros tipos de retorno sejam permitidos, nesse caso a variável de ambiente que possui o valor de retorno não será especificada. Mas se um programador fazreturn 0;
isso no bash, pode ser usado para criar ramificações.Se você realmente tiver problemas relacionados à eficiência de retornar um número inteiro de um processo, provavelmente evite chamar esse processo tantas vezes que esse valor de retorno se torne um problema.
Se você estiver fazendo isso (chame um processo tantas vezes), deverá encontrar uma maneira de colocar sua lógica diretamente dentro do chamador ou em um arquivo DLL, sem alocar um processo específico para cada chamada; as várias alocações de processos trazem a você o problema de eficiência relevante nesse caso.
Em detalhes, se você quiser apenas saber se retornar 0 é mais ou menos eficiente que retornar 1, em alguns casos, pode depender do compilador, mas genericamente, supondo que sejam lidos da mesma fonte (local, campo, constante, incorporado). no código, resultado da função etc.) requer exatamente o mesmo número de ciclos de relógio.
fonte
Aqui está uma pequena demonstração do uso de códigos de retorno ...
Ao usar as várias ferramentas fornecidas pelo terminal Linux, é possível usar o código de retorno, por exemplo, para tratamento de erros após a conclusão do processo. Imagine que o seguinte arquivo de texto myfile esteja presente:
Quando você executa o comando grep, um processo é criado. Uma vez concluído (e não quebrou), ele retorna algum código entre 0 e 255. Por exemplo:
Se você fizer
você receberá um 0. Por quê? Como o grep encontrou uma correspondência e retornou um código de saída 0, que é o valor usual para sair com êxito. Vamos dar uma olhada novamente, mas com algo que não está dentro do nosso arquivo de texto e, portanto, nenhuma correspondência será encontrada:
Como o grep falhou ao combinar o token "foo" com o conteúdo do nosso arquivo, o código de retorno é 1 (este é o caso usual em que ocorre uma falha, mas conforme indicado acima, você tem muitos valores para escolher).
Agora, o seguinte script bash (simplesmente digite-o em um terminal Linux), apesar de muito básico, deve dar uma idéia do tratamento de erros:
Após a segunda linha, nada é impresso no terminal, já que "foo" fez o grep retornar 1 e verificamos se o código de retorno do grep era igual a 0. A segunda instrução condicional ecoa sua mensagem na última linha, pois é verdadeira devido a CHECK == 1.
Como você pode ver se está chamando esse e aquele processo, às vezes é essencial ver o que ele retornou (pelo valor de retorno de main ()).
fonte
if grep foo myfile; then echo 'Match found'; else echo 'No match was found'; fi
- testando o status de retorno diretamente. Se você deseja capturar o status (para relatórios, etc), usa uma atribuição. Você pode usarif grep foo myfile; CHECK=$?; [ "$CHECK" = 0 ]; then echo 'Match found'; else echo 'No match was found'; fi
ou pode usar três linhas. Você também pode usar as opções-s
e-q
paragrep
impedir que correspondências ou mensagens de erro de rotina apareçam. No entanto, essas são minúcias do shell - o ponto principal, que o status de saída pode ser útil - está OK.Essas palavras "(mais eficientes)" não mudam a questão. A menos que você esteja em um ambiente independente, existe uma maneira universalmente correta de declarar
main()
, e é como retornar int.Não é o que deve
main()
retornar, é o que fazmain()
retorno.main()
é, obviamente, uma função que alguém chama. Você não tem nenhum controle sobre o código que chamamain()
. Portanto, você deve declararmain()
com uma assinatura do tipo correto para corresponder ao chamador. Você simplesmente não tem escolha no assunto. Você não precisa se perguntar o que é mais ou menos eficiente, ou o que é melhor ou pior, ou algo assim, porque a resposta já está perfeitamente bem definida, para você, pelos padrões C e C +. Apenas siga-os.0 para sucesso, diferente de zero para falha. Novamente, não é algo que você precisa (ou consegue) escolher: é definido pela interface com a qual você deveria estar em conformidade.
fonte