Qual é a declaração apropriada de main?

147

Qual é a assinatura adequada da mainfunção em C ++? Qual é o tipo de retorno correto e o que significa retornar um valor main? Quais são os tipos de parâmetros permitidos e quais são seus significados?

Este sistema é específico? Essas regras mudaram com o tempo? O que acontece se eu violá-los?

fredoverflow
fonte
1
Isso está intimamente relacionado ou uma duplicata do que deve mainretornar em C e C ++ .
Jonathan Leffler
@JonathanLeffler Sem brincadeira ... foi adicionado à lista de duplicatas na revisão 6 cerca de 8 meses atrás.
Fredoverflow 18/05

Respostas:

192

A mainfunção deve ser declarada como uma função não membro no espaço para nome global. Isso significa que ela não pode ser uma função de membro estática ou não estática de uma classe, nem pode ser colocada em um espaço para nome (mesmo no espaço para nome sem nome).

O nome mainnão está reservado no C ++, exceto como uma função no espaço para nome global. Você pode declarar outras entidades nomeadas main, incluindo, entre outras coisas, classes, variáveis, enumerações, funções de membro e funções de não membro que não estão no espaço de nomes global.

Você pode declarar uma função nomeada maincomo uma função membro ou em um espaço para nome, mas essa função não seria a mainfunção que designa onde o programa é iniciado.

A mainfunção não pode ser declarada como staticou inline. Também não pode ser sobrecarregado; pode haver apenas uma função nomeada mainno espaço para nome global.

A mainfunção não pode ser usada no seu programa: você não pode chamar a mainfunção de qualquer lugar do seu código, nem o endereço dele.

O tipo de retorno de maindeve serint . Nenhum outro tipo de retorno é permitido (esta regra está em negrito porque é muito comum ver programas incorretos que são declarados maincom um tipo de retorno void; essa é provavelmente a regra mais frequentemente violada em relação à mainfunção).

Há duas declarações mainque devem ser permitidas:

int main()               // (1)
int main(int, char*[])   // (2)

Em (1) , não há parâmetros.

Em (2) , existem dois parâmetros e eles são nomeados convencionalmente argce argv, respectivamente. argvé um ponteiro para uma matriz de seqüências de caracteres C representando os argumentos do programa. argcé o número de argumentos na argvmatriz.

Geralmente, argv[0]contém o nome do programa, mas esse nem sempre é o caso. argv[argc]é garantido para ser um ponteiro nulo.

Observe que, como um argumento do tipo array (como char*[]) é realmente apenas um argumento do tipo ponteiro disfarçado, as duas seguintes são maneiras válidas de escrever (2) e ambas significam exatamente a mesma coisa:

int main(int argc, char* argv[])
int main(int argc, char** argv)

Algumas implementações podem permitir outros tipos e números de parâmetros; você precisaria verificar a documentação da sua implementação para ver o que ela suporta.

main()é esperado que retorne zero para indicar sucesso e diferente de zero para indicar falha. Não é necessário que você escreva explicitamente uma returndeclaração main(): se você deixar main()retornar sem uma returndeclaração explícita , será o mesmo que se você tivesse escrito return 0;. As duas main()funções a seguir têm o mesmo comportamento:

int main() { }
int main() { return 0; }

Existem duas macros EXIT_SUCCESSe EXIT_FAILURE, definidas nela, <cstdlib>também podem ser retornadas main()para indicar sucesso e falha, respectivamente.

O valor retornado por main()é passado para a exit()função, que finaliza o programa.

Observe que tudo isso se aplica somente ao compilar para um ambiente hospedado (informalmente, um ambiente em que você tenha uma biblioteca padrão completa e um SO executando o seu programa). Também é possível compilar um programa C ++ para um ambiente independente (por exemplo, alguns tipos de sistemas incorporados), caso em que a inicialização e a finalização são totalmente definidas pela implementação e uma main()função pode nem ser necessária. Porém, se você estiver escrevendo C ++ para um sistema operacional de desktop moderno, estará compilando para um ambiente hospedado.

James McNellis
fonte
1
IIRC, os únicos valores de retorno garantidos são 0, EXIT_SUCCESS (o mesmo efeito que 0) e EXIT_FAILURE. EDIT: Ah, OK, outros valores de status diferentes de zero podem ser retornados, mas com significado definido pela implementação. Somente EXIT_FAILURE é garantido para ser interpretado de alguma forma como um valor de falha.
Derrick Turk
4
@ Synetech: A pergunta pergunta em sua primeira frase: "Qual é a assinatura apropriada da função principal em C ++?" e a pergunta está marcada com [c ++] e [c ++ - faq]. Não posso evitar que usuários de Java ou C # (ou qualquer outra pessoa) ainda estejam confusos. O C # exige Mainser uma função membro estática porque nem sequer possui funções que não sejam membros. Até o C89 precisa mainretornar int. Eu não estou suficientemente familiarizado com a K&R C para saber suas regras exatas, mas acho que também exige mainretornar, intpois mainsem tipo de retorno era algo comum e nenhum tipo = implícito intna K&R.
James McNellis
3
@ Suhail: porque o padrão de idioma diz que o tipo de retorno deve ser int.
James McNellis
1
@ Suhail: Sim. Seu código não estará correto em C ++ e muitos compiladores rejeitarão seu código.
James McNellis
2
@ Suhail: Visual C ++ permite um voidtipo de retorno como uma extensão de idioma . Os compiladores que não permitem isso incluem o GCC e o Comeau.
James McNellis
15

Nos documentos padrão, 3.6.1.2 Função principal ,

Deve ter um tipo de retorno do tipo int, mas, caso contrário, seu tipo é definido pela implementação. Todas as implementações devem permitir as duas seguintes definições de main:

int main() { / ... / } e int main(int argc, char* argv[]) { / ... / }

Na última forma, argcserá o número de argumentos passados ​​para o programa a partir do ambiente em que o programa é executado. Se argc for diferente de zero, esses argumentos deverão ser fornecidos em argv [0] a argv [argc-1] como ponteiros para o inicial caracteres de cadeias multibyte terminadas em nulo .....

Espero que ajude..

liaK
fonte
2
Existe algum motivo específico para o motivo pelo qual o tipo de retorno main deve ser int?
Suhail Gupta 15/06
1
@SuhailGupta: Para que o processo de chamada saiba se esse processo deve ser considerado bem-sucedido ou não. Permitir voidquebras esse modelo. Realmente nem faz sentido se você quer dizer "sempre considere o sucesso". Como você não tinha como dizer se o processo realmente falhou, você realmente conseguiu? Não retornoint .
Lightness Races in Orbit
4

A redação exata do último padrão publicado (C ++ 14) é:

Uma implementação deve permitir tanto

  • uma função de ()retornar inte

  • uma função de (int, ponteiro para ponteiro para char)retornarint

como o tipo de main.

Isso deixa claro que grafias alternativas são permitidas desde que o tipo de mainseja o tipo int()ou int(int, char**). Portanto, o seguinte também é permitido:

  • int main(void)
  • auto main() -> int
  • int main ( )
  • signed int main()
  • typedef char **a; typedef int b, e; e main(b d, a c)
MILÍMETROS
fonte
1
NB Postei essa resposta como nos comentários de outro tópico, alguém tentou citar esse tópico como evidência que int main(void)não estava correta no C ++.
MM
3
@Stargateur auto main() -> intnão tem um tipo de retorno deduzido. Preste atenção ao {in "(auto main () {... não é permitido)" e aprenda a saber quando você ainda não sabe o suficiente para adicionar algo significativo.
3

As duas redes válidas são int main()e int main(int, char*[]). Qualquer outra coisa pode ou não ser compilada. Se mainnão retornar explicitamente um valor, 0 será retornado implicitamente.

pedregoso
fonte
1
Eu nunca vi código não sendo compilado quando menciono o tipo de retorno de mainser nulo. Existe algum motivo específico para que o tipo de retorno principal seja int?
Suhail Gupta 15/06
4
A especificação da linguagem diz que main deve ter um tipo de retorno int. Qualquer outro tipo de retorno permitido pelo seu compilador é um aprimoramento específico do compilador. Basicamente, o uso de void significa que você está programando em uma linguagem semelhante, mas não C ++.
stonemetal
2
O motivo pelo qual o padrão exige um inttipo de retorno mainé que esse valor é entregue ao shell como o código de saída do programa e shespera um int.
Uckelman
Talvez o motivo seja a disciplina? Pode haver mais de um caminho. Se o tipo de retorno for voidtodos eles são silenciosos. Com intnós temos que definir o valor de saída específico para cada retorno de main.
Andreas Spindler
2

Detalhes sobre valores de retorno e seu significado

Conforme 3.6.1 ( [basic.start.main]):

Uma declaração de retorno em maintem o efeito de deixar a mainfunção (destruindo qualquer objeto com duração de armazenamento automático) e chamar std::exitcom o valor de retorno como argumento. Se o controle chegar ao fim mainsem encontrar uma returndeclaração, o efeito é o de executar

return 0;

O comportamento de std::exité detalhado na seção 18.5 ( [support.start.term]) e descreve o código de status:

Por fim, o controle é retornado ao ambiente host. Se o status for zero ou EXIT_SUCCESS, uma forma definida pela implementação do status de finalização bem-sucedida será retornada. Se status for EXIT_FAILURE, será retornada uma forma definida pela implementação do encerramento sem êxito do status. Caso contrário, o status retornado é definido pela implementação.

Ben Voigt
fonte