Может ли главная функция вызывать себя на С++?

Может кто-нибудь сказать, в чем проблема с кодом ниже?

int main () { 
    return main(); 
}

Я тестировал, он компилируется правильно. Он работает вечно. Неповторимый трюк за сценой?

Ответ 1

TL;DR. Вызов main приводит к поведению undefined.


Похоже, что существует путаница в терминологии, используемой в стандарте, и о последствиях для программиста и компилятора.

Во-первых, стандарт самостоятельно определяет все, что касается языка С++. Если ваша конкретная версия конкретного компилятора допускает какое-то конкретное действие, которое не имеет никакого отношения к тому, является ли это действие законным. Для остальной части сообщения я имею в виду стандарт ISO03.

Итак, чтобы еще раз процитировать, стандарт гласит в п. 3.3.1.3:

Функция main не должна использоваться внутри программы.

Кроме того, в §3.2 "используется" как:

Объект или неперегруженная функция используется, если его имя отображается в потенциально вычисленном выражении.

Это означает, что, как только программа начнет выполнение, main должен никогда не вводиться снова. Это означает, что программисты не могут вызывать main, это значит, что компилятор не может вставить другой вызов main (почему он будет, кто знает), вы не можете взять адрес main и позвонить, и т.д. У вас даже не может быть потенциала вызов main.

Единственный вызов main должен выполняться библиотекой времени выполнения, в которой запущена программа; все остальные вызовы вызывают поведение undefined. (Это означает, что все может случиться!)


Теперь о поведении компилятора:

Диагностическое правило определяется как (§1.4.1):

Набор диагностируемых правил состоит из всех синтаксических и семантических правил в этом Международном стандарте, за исключением тех правил, которые содержат явное обозначение, что "никакой диагностики не требуется" или которые описаны как результат "undefined поведения".

В нашем случае в п. 3.3.1.3 определяется правило диагностики. Вот какие компиляторы должны делать в соответствии с §1.4.2:

- Если программа не содержит нарушений правил в этом Международном стандарте, соответствующая реализация должна в пределах своих ресурсов принимать и правильно выполнять3) эту программу.
- Если программа содержит нарушение любого диагностируемого правила, соответствующая реализация должна выпустить хотя бы одно диагностическое сообщение, за исключением того, что - Если программа содержит нарушение правила, для которого не требуется диагностика, настоящий международный стандарт не устанавливает требований к реализации в отношении этой программы.

Поэтому компиляторы не обязаны применять правила. Все компиляторы должны сделать, это взять хорошо сформированные программы (§1.3.14) и превратить их в исполняемую программу. Компилятор может свободно предупреждать, ошибочно и т.д., Однако ему нравится, если он не конфликтует с языком. В соответствии со вторым предложением необходимо отобразить сообщение в нашем конкретном случае.

Для этой конкретной задачи на gcc параметр -pedantic будет предупреждать о незаконности вызова main внутри программы. Visual Studio не будет предупреждать о вызове main, но на любом уровне предупреждения (больше 0) он будет предупреждать о рекурсивном характере программы.


Что все это означает с точки зрения ответов, которые вы должны ожидать? Это означает, что совершенно бессмысленно пытаться определить с уверенностью то, что опубликует фрагмент кода. Вызов main приводит к поведению undefined, и попытка определения поведения undefined, очевидно, является потерянной причиной. Единственный честный ответ, который любой может дать "что происходит, когда я называю main?"? "Что угодно".

Надеюсь, это прояснит ситуацию.

Ответ 2

Вызов main в С++ является незаконным (§3.6.1.3):

Функция main не должна использоваться внутри программы.

Ваш компилятор разрешает незаконное поведение.

Он циклически навсегда, потому что, main вызывает main, который вызывает main, который вызывает main и т.д.

Ответ 3

Ему нравится быть наркодилером. Довольно незаконно, но компилируется и даже работает хорошо в течение некоторого времени...

Ответ 4

Вопрос в том, зачем вы хотите?

main должна быть единственной точкой входа для вашей программы. Вызов его снова существенно перезапустит вашу программу, но без нового экземпляра процесса; нет нового стека, нет новой кучи и т.д.

Если вам действительно нужна рекурсия, вызовите отдельную функцию рекурсивно.

Ответ 5

В стандарте С++ в разделе 3.6.1 говорится:

Функция main не должна использоваться (3.2) внутри программы.

Он указывает, что вы не должны вызывать его из вашей программы.

Ответ 6

Конечно, если вы действительно хотите рекурсивно вызывать свою основную функцию, и иногда есть веские причины, вы должны просто сделать это

int mymain()
{
  return mymain();
}

int main()
{
   return mymain();
}

Ответ 7

Когда вы пишете рекурсивный код, вам нужно убедиться, что в какой-то момент вы перестанете рекурсировать, иначе вы просто написали бесконечный цикл.

Что у вас есть.

Вы должны ожидать, что этот код уйдет в течение длительного времени, а затем, наконец, сбой при переполнении стека.

Ответ 8

У вас есть два вопроса. Первый - это вызов main, который, как уже указывалось, нарушает стандарт и цель стандарта.

Большая проблема заключается в том, что вы написали рекурсивный вызов без какой-либо точки закрытия. Вы сомневаетесь, что предположите, что версия main, вызванная исходной, просто вернется. Однако большинство языков (на самом деле все, о чем я могу думать) допускает неограниченную рекурсию: если функция вызывает себя, то эта версия будет также. Единственным ограничением является системные ресурсы.

Итак, вам нужно обернуть вызов в условном выражении и продолжать звонить только при необходимости. В вашем примере будет добавлено глобальное целое число, установленное на количество уровней, которые вы хотите обработать. Что-то вроде этого:

`

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

`

Выйдет.

Ответ 9

Несмотря на то, что ваша программа явно не имеет смысла, поскольку она навсегда навсегда, возможно, будет возможно сделать что-то вроде:

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
   }
}

Однако стандарт запрещает его. (См. Другие ответы)

Конечно, вы можете реализовать это, сделав это

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