9

我正在编写 C 脑预告片:编写标准的 Hello-World 程序,不带分号。

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

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

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

error C4716: 'main' : must return a value

我尝试了其他声明了返回类型但缺少返回语句的函数,并得到了这个编译器错误。


请注意,我也尝试过:

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

int main(void)
{
    foo();
}

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

4

6 回答 6

9

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

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

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

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

在 C++ 中,该main()函数被特殊处理,因为return 0;在右大括号之前有一个隐式。

我怀疑微软的 C 编译器在 C 模式下编译时提供了相同的处理(如果你查看汇编代码,即使没有 EAX 寄存器也会被清除return 0;),因此就编译器而言,没有理由发布警告 C4716。请注意,Microsoft 的 C 模式是 C90 兼容的,而不是 C99 兼容的。在 C90 中,“跑完”main()有未定义的行为。但是,始终返回 0 满足未定义行为的低要求,因此没有问题。

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


原始的,不太好的答案:

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

所以如果编译成 C++ 或者 C99 就没有错误,和return 0;. C90 导致未定义的行为(不需要诊断)。

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

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

于 2009-01-29T21:56:56.850 回答
6

如果您不返回任何内容,程序将返回 0。请参阅http://www.research.att.com/~bs/bs_faq2.html#void-main

于 2009-01-29T21:13:24.647 回答
2

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

于 2009-01-29T21:16:35.810 回答
1

因为这不是错误——它是未定义的行为。请参阅 C99 标准的第 6.9.1 节第 12 段:

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

因此,当看到您的代码无法返回时,编译器可以自由地做任何事情——它可以发出错误、警告或根本不发出任何东西。在 GCC 的情况下,它默认编译成功,没有警告或错误。使用该-Wall选项,它会发出警告。

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

第 5.1.2.2.3 节:

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

于 2009-01-29T21:24:02.783 回答
1

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

C++ 语言参考

退出函数

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

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

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

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


于 2009-01-29T21:36:20.933 回答
1

由于各种原因,不从 main 返回,或者更准确地说,没有到达 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或类似的。

于 2012-05-12T16:30:47.970 回答