主函数可以在C ++中调用自身吗?

时间:2010-01-24 19:09:35

标签: c++

有谁可以告诉下面的代码有什么问题?

int main () { 
    return main(); 
}

我测试过,它编译正确。它一直在运行。现场背后的诀窍呢?

9 个答案:

答案 0 :(得分:36)

TLDR :调用main会导致未定义的行为。


标准中使用的术语似乎存在混淆,以及对程序员和编译器的影响。

首先,标准决定了C ++语言的一切。如果特定编译器的特定版本允许某些特定操作,则与该操作是否合法无关。对于帖子的其余部分,我指的是ISO03标准。

所以再次引用,标准在§3.6.1.3中说:

  

函数main不得在程序中使用。

此外,§3.2将“used”定义为:

  

如果对象或非重载函数的名称出现在可能已评估的表达式中,则使用该函数。

这意味着一旦程序开始执行,main 永远不会再次输入。这意味着程序员无法调用main,这意味着编译器无法插入另一个调用main(为什么会这样,谁知道),你不能取主要地址并调用它等等。你甚至不能有可能打电话给main

main的唯一调用应该是程序运行的运行时库;所有其他调用都会调用未定义的行为。 (这意味着任何事情都可能发生!)


现在进入编译器行为:

可诊断规则定义为(§1.4.1):

  

可诊断规则集包含本国际标准中的所有语法和语义规则,但那些包含“无需诊断”的明确表示法或描述为“未定义行为”的规则除外。

在我们的案例中,§3.6.1.3定义了可诊断的规则。以下是编译器应根据§1.4.2进行的操作:

  

- 如果某个程序不违反本国际标准中的规则,则符合条件的实施应在其资源限制内接受并正确执行该程序。
   - 如果程序包含违反任何可诊断规则的行为,则符合要求的实施应至少发出一条诊断消息,但该除外    - 如果某个程序违反了不需要诊断的规则,则本国际标准不对该程序的实施提出任何要求。

因此编译器需要强制执行规则。所有编译器必须做的是采用格式良好的程序(§1.3.14)并将它们转换为可执行程序。编译器可以自由地发出警告,错误等等,只要它不与语言冲突。根据第二个条款, required 在我们的特定情况下显示消息。

对于这个特殊问题,在gcc上-pedantic选项会警告在程序中调用main的非法性。 Visual Studio不会警告调用main,但在任何警告级别(大于0)上它都会警告该程序的递归性质。


对于您应该期待的答案,这一切意味着什么?这意味着尝试确定代码片段发布的内容是完全没有意义的。调用main会导致未定义的行为,并且尝试定义未定义的行为显然是一个失败的原因。任何人都可以给出的唯一诚实的答案是“当我致电main时会发生什么?”是“一切。”

我希望这能解决问题。

答案 1 :(得分:24)

在C ++中调用main是非法的(§3.6.1.3):

  

函数main不得在程序中使用。

您的编译器允许非法行为。

它永远循环,因为main调用main,调用main,调用main,依此类推。

答案 2 :(得分:9)

就像是一个贩毒者。非常非法,但编译甚至可以在一段时间内发挥作用......

答案 3 :(得分:4)

问题是,你为什么要这样做?

main应该是您程序的单个入口点。再次调用它本质上会重新启动您的程序,但没有新的流程实例;没有新堆栈,没有新堆等。

如果您确实需要递归,请递归调用单独的函数。

答案 4 :(得分:4)

C ++标准,在3.6.1节中说:

  

在程序中不得使用函数main(3.2)。

它指定,您不应该在程序中调用它。

答案 5 :(得分:4)

当然如果你真的想要递归调用你的main函数,有时候有充分的理由,你应该这样做

int mymain()
{
  return mymain();
}

int main()
{
   return mymain();
}

答案 6 :(得分:2)

当您编写递归代码时,您需要确保在某些时候停止递归,否则您只是编写了一个无限循环。

你有哪些。

您应该期望此代码在 long 时间消失,然后最终因堆栈溢出而崩溃。

答案 7 :(得分:1)

你有两个问题。第一个是调用main,正如已经指出的那样,它们都违反了标准的标准和意图。

更大的问题是你写了一个没有任何关闭点的递归调用。你的问题似乎假设初始版本调用的main版本将返回。但是,大多数语言(事实上我只能想到)允许无限递归:如果函数调用自身,那么该版本也将如此。唯一的限制是系统资源。

因此,您需要在条件中包装调用,并在需要时继续调用。在您的示例中,将全局整数集添加到要递归的级别数将起作用。像这样:

`

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

`

将退出。

答案 8 :(得分:0)

虽然你的程序显然没有任何意义,因为它永远循环,但它可能看似可行:

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
}