为什么没有编译器错误的main()没有返回结束?

我正在研究C-brain预告片:编写标准的Hello-World程序,没有分号。

到目前为止我的最佳答案是:

int main(void) { if (printf("Hello World!\n"), exit(0), 0) { /* do nothing */ } } 

但我不明白为什么我没有得到编译器错误(Visual Studio):

 error C4716: 'main' : must return a value 

我已尝试使用声明的返回类型的其他函数,但缺少return语句,并得到此编译器错误。


请注意,我也尝试过:

 int foo(void) { if (printf("Hello World!\n"), exit(0), true) { /* do nothing */ } } int main(void) { foo(); } 

并且不要在foo上得到编译器错误。 如果我删除“exit(0)”,我确实得到了编译器错误。 显然编译器知道“退出”是一个特殊function? 这对我来说似乎很奇怪。

正如Jens在评论中指出的那样,发布的代码没有表现出未定义的行为。 这里的原始答案是不正确的,甚至似乎都没有回答这个问题(几年之后重新阅读所有内容)。

这个问题可以概括为“为什么MSVC不会在与其他function相同的情况下发出针对main()警告C4716”?

请注意,诊断C4716是警告,而不是错误。 就C语言而言(无论如何从标准的角度来看),从来没有要求诊断非错误。 但这并没有真正解释为什么会有差异,这只是一种技术性,可能意味着你不能抱怨太多……

MSVC为其他函数执行操作时,为什么MSVC不发出main()警告的真正解释实际上只能由MSVC团队的某个人来回答。 据我所知,文档并没有解释差异,但也许我错过了一些东西; 所以我能做的就是推测:

在C ++中, main()函数被特别处理,因为它有一个隐式return 0; 就在结束支架之前。

我怀疑微软的C编译器在C模式下进行编译时提供相同的处理方法(如果查看汇编代码,即使没有return 0; ,EAX寄存器也会被清除return 0; )因此,就编译器而言,没有有理由发出警告C4716。 请注意,Microsoft的C模式符合C90标准,而不符合C99标准。 在C90’main main() ‘结束’运行具有未定义的行为。 但是,始终返回0满足未定义行为的低要求,因此没有问题。

因此,即使问题中的程序确实从最终的main() (导致未定义的行为),仍然不会有警告。


原来,不是那么好的答案:

在ANSI / ISO 90 C中,这是未定义的行为,因此MS确实应该产生错误(但标准不要求它们)。 在C99中,标准允许在main()结束时隐含return – 与C ++一样。

因此,如果将其编译为C ++或C99,则没有错误,它与return 0;相同return 0; 。 C90导致未定义的行为(不需要诊断)。

有趣的是(好吧,也许不是),在几个编译器(VC9,VC6,GCC 3.4.5,Digital Mars,Comeau)中,我尝试使用我的基本,主要是默认选项集(我几乎总是使用的环境 – 代码片段的n-dirty测试)当编译为C ++程序时,唯一警告缺少返回语句的编译器是VC6(VC6在编译C时不会抱怨)。

如果函数未命名为main则大多数编译器会抱怨(警告或错误)。 编译C时的数字火星没有,GCC不适用于C或C ++。

如果你没有返回任何东西,程序将返回0.请参阅http://www.research.att.com/~bs/bs_faq2.html#void-main

编译可能足够聪明,知道正在调用exit(0),它永远不会返回,因此不需要它。

来自http://msdn.microsoft.com/en-us/library/k9dcesdd(VS.71).aspx

C ++语言参考

退出function

在标准包含文件STDLIB.H中声明的exit函数终止了一个C ++程序。

作为退出参数提供的值将作为程序的返回代码或退出代码返回给操作系统。 按照惯例,返回码为零意味着程序成功完成。

注意您可以使用STDLIB.H中定义的常量EXIT_FAILURE和EXIT_SUCCESS来指示程序的成功或失败。

从main函数发出return语句相当于以返回值作为参数调用exit函数。


因为它不是错误 – 它是未定义的行为。 见C99标准第6.9.1节第12段:

如果到达终止函数的},并且调用者使用函数调用的值,则行为是未定义的。

因此,当看到代码无法返回时,编译器可以随心所欲地执行任何操作 – 它可以发出错误,警告或根本不发送任何内容。 对于GCC,它默认成功编译,没有警告或错误。 使用-Wall选项,它会发出警告。

main()在C中是特殊的:它是唯一允许不返回值的函数。 C标准表示如果控制在没有return语句的情况下到达main()的末尾,则它会隐式返回0.这仅适用于main() ,所有其他非void函数必须返回一个值。

第5.1.2.2.3节:

如果main函数的返回类型是与int兼容的类型,则从初始调用返回main函数等效于调用exit函数,其中main函数返回的值作为其参数; 10)到达}终止main函数返回值0.如果返回类型与int不兼容,则返回到主机环境的终止状态未指定。

不是从main返回,或者更准确地说,没有到达主函数的终止’}’,由于各种原因完全没问题。 典型案例包括永久循环,退出或中止之前。

在这种情况下,保证在到达main结束之前执行exit(0) 。 编译器为什么要警告? 你不会期待这些警告,不是吗?

 int main (void) { for (;;) { /* do something useful */ } } int main (void) { /* do something */; exit (0); } 

如果,我甚至会感到惊讶

 int main (void) { if (printf("Hello World!\n"), exit(0), true) { /* do nothing */ } return 0; } 

不会引起warning: unreachable code: return 0或某些。