主函数可以在C ++中调用自己吗?
有人可以告诉下面的代码有什么问题吗?
int main () { return main(); }
我testing过,它编译正确。 它永远在运行。 幕后的诡计呢?
TLDR :调用未定义行为的main
结果。
标准中使用的术语似乎有点混淆,对编程人员和编译人员也有影响。
首先, 标准本身决定了关于C ++语言的一切。 如果特定编译器的特定版本允许进行某些特定的操作,则与该操作是否合法无关。 对于这篇文章的其余部分,我指的是ISO03标准。
所以再次引用,标准在§3.6.1.3中说:
函数main不能在程序中使用。
另外,§3.2将“used”定义为:
如果对象或非重载函数的名称出现在潜在评估的expression式中,则使用该函数。
这意味着一旦程序开始执行, main
不会再被input 。 这意味着程序员不能调用main
,这意味着编译器不能插入另一个调用main
(为什么会这样,谁知道),你不能把main的地址和调用这个地址等等,你甚至不可能调用main
。
对main
的唯一调用应该是程序运行的运行时库; 所有其他调用都会调用未定义的行为。 (这意味着会发生任何事情!)
现在编译器的行为:
可诊断规则定义为(§1.4.1):
一套可诊断的规则由本国际标准中的所有句法和语义规则组成,除了那些包含“不需要诊断”或被描述为导致“未定义的行为”的明确标记的规则。
在我们的例子中,§3.6.1.3定义了一个可诊断的规则。 以下是根据§1.4.2,编译器应该做的事情:
– 如果一个程序没有违反本标准中的规则,那么符合规定的实施应在其资源限制内接受并正确执行该程序。
– 如果某个程序违反了任何可诊断的规则,则符合规定的实施至less应发出一条诊断消息
– 如果一个程序违反了不需要诊断的规则,本国际标准没有要求实施该程序。
所以编译器不需要执行规则。 所有编译器所要做的就是将格式良好的程序 (§1.3.14)转换成可执行程序。 编译器可以自由地发出警告,错误等等,但是只要它不与语言冲突,它就是喜欢的。 根据第二条款,我们需要在特定情况下显示一条消息。
对于这个特殊的问题,在gcc上, -pedantic
选项会警告在程序中调用main
的非法性。 Visual Studio不会警告调用main
,但是在任何警告级别(大于0)时,它都会警告程序的recursion性质。
这一切意味着你应该期待的答案是什么? 这意味着尝试确定代码片段将做什么是完全没有意义的。 调用未定义行为的main
结果,并试图定义未定义的行为显然是一个失败的原因。 只有诚实的回答,任何人都可以给“当我打电话时发生什么? 是“什么”。
我希望这个清理的事情。
在C ++中调用main
是非法的(§3.6.1.3):
函数main不能在程序中使用。
你的编译器允许非法行为。
它永远循环,因为, main
调用main
,谁调用main
,谁调用main
,等等。
这就像是一个毒贩。 非常不合法,但是编译甚至编译好一段时间…
问题是,你为什么要?
主应该是你的程序的一个入口点。 再次调用它会重新启动您的程序,但不会有新的stream程实例; 没有新的堆栈,没有新的堆等
如果你真的需要recursion,recursion地调用一个单独的函数。
C ++标准在3.6.1节中说:
程序中不能使用function主(3.2)。
它规定,你不应该从你的程序中调用它。
当然,如果你真的想recursion地调用你的主函数,有时候有很好的理由,你应该这样做
int mymain() { return mymain(); } int main() { return mymain(); }
当你编写recursion代码时,你需要确保在某个时候停止recursion,否则你就写了一个无限循环。
你有。
你应该期望这个代码长时间消失,然后最终崩溃堆栈溢出。
你有两个问题。 首先是调用主体,正如已经指出的那样,都违反了标准的标准和意图。
更大的问题是你写了一个没有任何closures点的recursion调用。 你的问题似乎认为,由最初的一个调用的主版本将只是返回。 然而,大多数语言(实际上我能想到的)允许无限recursion:如果一个函数自己调用,那么该版本也是如此。 唯一的限制是系统资源。
所以你需要将这个调用包装在一个条件中,并且只在需要的时候继续调用。 在你的例子中,添加一个全局整数设置为您要recursion的级别的数量将工作。 像这样的东西:
`
int levels = 3; int main() { if(levels) { cout << "Recursing another level...\n"; levels--; main(); } else { cout << "Reached the bottom.\n"; } return levels; }
`
将退出。
虽然你的程序显然是没有意义的,因为它永远循环,看起来可行的做一些事情,如:
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 }