A function principal pode se chamar em C ++?

Alguém pode dizer qual é o problema do código abaixo?

int main () { return main(); } 

Eu testei, ele compila corretamente. Está correndo para sempre. Mais truque por trás da cena?

TLDR : Chamando os main resultados em comportamento indefinido.


Parece haver confusão sobre a terminologia usada no padrão e as implicações que isso tem para o programador e o compilador.

Em primeiro lugar, o padrão sozinho determina tudo sobre a linguagem C ++. Se a sua versão particular de um compilador específico permitir alguma ação específica, isso não tem importância se essa ação é legal ou não. Para o restante do post, estou me referindo ao padrão ISO03.

Então, para citar mais uma vez, a norma diz em §3.6.1.3:

A function main não deve ser usada dentro de um programa.

Além disso, §3.2 define “usado” como:

Um object ou function não sobrecarregada é usado se seu nome aparecer em uma expressão potencialmente avaliada.

Isso significa que, uma vez que o programa comece a ser executado, o main nunca deve ser inserido novamente . Isso significa que os programadores não podem chamar main , isso significa que o compilador não pode inserir outra chamada para main (por que, quem sabe), você não pode pegar o endereço de main e chamá-lo, etc. Você não pode nem ter o potencial de chamar main .

A única chamada para main deve ser pela biblioteca de tempo de execução em que o programa está sendo executado; todas as outras chamadas invocam um comportamento indefinido. (O que significa que tudo pode acontecer!)


Agora no comportamento do compilador:

Uma regra diagnosticável é definida como (§1.4.1):

O conjunto de regras diagnosticáveis ​​consiste em todas as regras sintáticas e semânticas nesta Norma Internacional, exceto aquelas regras que contêm uma notação explícita de que “nenhum diagnóstico é necessário” ou que são descritas como resultando em “comportamento indefinido”.

No nosso caso, §3.6.1.3 define uma regra diagnosticável. Veja o que os compiladores devem fazer de acordo com o §1.4.2:

– Se um programa não contiver violações das regras desta Norma, uma implementação conforme deverá, dentro de seus limites de resources, aceitar e executar corretamente3) aquele programa.
– Se um programa contiver uma violação de qualquer regra diagnosticável, uma implementação conforme deverá emitir pelo menos uma mensagem de diagnóstico, exceto que
– Se um programa contiver uma violação de uma regra para a qual não é necessário diagnóstico, este Padrão Internacional não impõe nenhuma exigência sobre implementações com relação a esse programa.

Portanto, os compiladores não são obrigados a impor regras. Todos os compiladores têm que fazer é tomar programas bem formados (§1.3.14) e transformá-los em um programa executável. Um compilador está livre para avisar, erro, etc., por mais que goste, desde que não entre em conflito com a linguagem. É necessário exibir uma mensagem em nosso caso particular, de acordo com a segunda cláusula.

Para este problema em particular, no gcc, a opção -pedantic irá alertar sobre a ilegalidade de chamar main dentro do programa. O Visual Studio não avisará sobre a chamada main , mas em qualquer nível de aviso (maior que 0), ele avisará sobre a natureza recursiva do programa.


O que tudo isso significa em termos das respostas que você deveria esperar? Isso significa que é completamente sem sentido tentar definir com certeza o que o snippet de código postado fará. Chamar os main resultados em comportamento indefinido e tentar definir um comportamento indefinido é obviamente uma causa perdida. A única resposta honesta que alguém pode dar ao “o que acontece quando eu chamo de main ?” é “qualquer coisa”.

Eu espero que isso esclareça as coisas.

Chamar main em C ++ é ilegal (§3.6.1.3):

A function main não deve ser usada dentro de um programa.

Seu compilador está permitindo um comportamento ilegal.

Ele faz um loop para sempre porque, bem, chamadas main , who chama main , who chama main e assim por diante.

É como ser um traficante de drogas. Muito ilegal, mas compila e até funciona bem por algum tempo …

A questão é, por que você quereria?

main é suposto ser um único ponto de input para o seu programa. Chamar de novo essencialmente reinicia seu programa, mas sem uma nova instância de processo; sem pilha nova, sem pilha nova, etc.

Se você realmente precisar de recursion, chame uma function separada recursivamente.

O padrão C ++, na seção 3.6.1, diz:

A function main não deve ser utilizada (3.2) dentro de um programa.

Ele especifica que você não deve chamá-lo de dentro do seu programa.

Claro, se você realmente quer chamar sua function principal de forma recursiva, e às vezes há boas razões, você deve apenas fazer isso

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

Quando você escreve código recursivo, você precisa ter certeza de que em algum momento você pare de recursar, caso contrário, você acabou de escrever um loop infinito.

Que você tem.

Você deve esperar que esse código desapareça por um longo tempo e, finalmente, travar com um estouro de pilha.

Você tem dois problemas. O primeiro chama-se main, o que, como já foi apontado, viola o padrão e a intenção do padrão.

O maior problema é que você escreveu uma chamada recursiva sem nenhum ponto de fechamento. Você pergunta parece assumir que a versão do principal chamado pelo inicial apenas retornará. No entanto, a maioria das linguagens (na verdade, tudo o que posso pensar) permitia a recursion ilimitada: se uma function chama a si mesma, essa versão também é válida. O único limite é resources do sistema.

Então você precisa envolver a chamada em uma condicional e só continuar a ligar quando necessário. No seu exemplo, adicionar um número inteiro global definido ao número de níveis que você deseja recorrer funcionaria. Algo assim:

`

 int levels = 3; int main() { if(levels) { cout < < "Recursing another level...\n"; levels--; main(); } else { cout << "Reached the bottom.\n"; } return levels; } 

`

Vai sair.

Embora o seu programa obviamente não faça sentido, uma vez que ele faz um loop para sempre, pode parecer viável fazer algo como:

 int main( int argc, char* argv[] ) { if( argc ) { // do something with argv[0] main( argc - 1, &argv[1] ); } else { // rest of application having loaded your arguments } } 

No entanto, o padrão não permite isso. (Veja outras respostas)

Claro que você pode implementar isso fazendo isso

 int myFunc( int argc, char * argv[] ) { // I can recurse this if I like and just get main to forward straight to here }