任何人都可以告诉下面的代码有什么问题吗?
int main () {
return main();
}
Run Code Online (Sandbox Code Playgroud)
我测试过,它编译正确.它一直在运行.现场背后的诀窍呢?
GMa*_*ckG 38
TLDR:调用main导致未定义的行为.
关于标准中使用的术语以及对程序员和编译器的含义似乎存在混淆.
首先,仅标准就决定了C++语言的一切.如果特定编译器的特定版本允许某些特定操作,则与该操作是否合法无关.对于帖子的其余部分,我指的是ISO03标准.
所以再次引用,标准在§3.6.1.3中说:
函数main不得在程序中使用.
另外,§3.2将"used"定义为:
如果对象或非重载函数的名称出现在可能已评估的表达式中,则使用该函数.
这意味着一旦程序开始执行,main就不应该再次输入.这意味着程序员无法调用main,这意味着编译器无法插入另一个调用main(为什么会这样,谁知道),你不能接受main的地址并调用它等等.你甚至无法调用它main.
唯一的调用main应该是程序运行的运行时库; 所有其他调用都会调用未定义的行为.(这意味着什么都可能发生!)
现在进入编译器行为:
可诊断规则定义为(§1.4.1):
可诊断规则集包含本国际标准中的所有语法规则和语义规则,但那些包含"无需诊断"的明确表示法或被描述为导致"未定义行为"的规则除外.
在我们的例子中,§3.6.1.3定义了可诊断的规则.以下是编译器应根据§1.4.2进行的操作:
- 如果某个程序不违反本国际标准中的规则,则符合要求的实施应在其资源限制内接受并正确执行该程序.
- 如果程序包含违反任何可诊断规则的行为,则符合要求的实施方案应至少发出一条诊断消息,但以下情况除外:
- 如果程序包含违反不需要诊断的规则,则本国际标准不要求实施关于该计划.
所以编译器不要求强制执行的规则.所有编译器必须做的是采用格式良好的程序(§1.3.14)并将它们转换为可执行程序.编译器可以自由地发出警告,错误等等,只要它不与语言冲突.据需要在我们的特定情况下,以显示消息,根据第二条款.
对于这个特殊问题,在gcc上,该-pedantic选项将警告main在程序内调用的非法性.Visual Studio不会警告调用main,但在任何警告级别(大于0),它将警告程序的递归性质.
对于你应该期待的答案,这一切意味着什么?这意味着尝试确定代码片段发布的内容是完全没有意义的.调用main导致未定义的行为,并尝试定义未定义的行为显然是一个失败的原因.任何人都可以给出的唯一诚实的答案是"当我打电话时会发生什么main?" 是"任何东西".
我希望这能解决问题.
GMa*_*ckG 24
main使用C++ 调用是非法的(§3.6.1.3):
函数main不得在程序中使用.
您的编译器允许非法行为.
它永远循环,因为,main呼叫main,呼叫main,呼叫main等等.
当然,如果您确实要递归调用主函数,并且有时出于某些原因,您应该这样做
int mymain()
{
return mymain();
}
int main()
{
return mymain();
}
Run Code Online (Sandbox Code Playgroud)
问题是,你为什么想要?
main 应该是您程序的单个入口点。再次调用它本质上会重新启动您的程序,但没有新的流程实例;没有新堆栈,没有新堆等。
如果你真的需要递归,递归调用一个单独的函数。