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

时间:2009-01-29 21:10:57

标签: c compiler-errors

我正在研究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)”,我会得到编译器错误。显然编译器知道“退出”是一个特殊的功能?这对我来说似乎很奇怪。

6 个答案:

答案 0 :(得分:9)

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

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

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

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

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

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

因此,即使问题中的程序运行结束main()(导致未定义的行为),仍然不会出现警告。


原创,答案不是很好:

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

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

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

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

答案 1 :(得分:6)

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

答案 2 :(得分:2)

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

答案 3 :(得分:1)

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

  

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

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

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

第5.1.2.2.3节:

  

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

答案 4 :(得分:1)

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

  

C ++语言参考

     

退出功能

     

退出函数,在。中声明   标准包括文件STDLIB.H,   终止C ++程序。

     

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

     

注意您可以使用常量   EXIT_FAILURE和EXIT_SUCCESS,已定义   在STDLIB.H中,表示成功或   你的程序失败了。

     

发出一个   来自主要的return语句   函数相当于调用   退出函数,返回值为   它的论点。


答案 5 :(得分:1)

由于各种原因,没有从main返回,或者更确切地说,没有返回主函数的终止'}'。典型案例包括永久循环,退出或中止之前。

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

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或某些事情。

相关问题