如果 main() 不返回 int 值会怎样?

Posted

技术标签:

【中文标题】如果 main() 不返回 int 值会怎样?【英文标题】:What happens if main() does not return an int value? 【发布时间】:2012-02-09 07:44:34 【问题描述】:

我知道在 C 编译器中,main() 函数由 _start() 函数调用,其代码如下:

exit(main()); // return value of main is returned

main() 不返回int_start() 如何工作,例如,如果它的返回类型是voidfloat 或其他什么?

【问题讨论】:

我会映像函数指针转换,但我想听听知道真相的人的意见。等不及答案了。 :D C和C++对main返回值的限制不同 @fefe - 真的吗?我认为两者都需要返回 int - 得到标准的 para 数字以便我可以阅读?我有 C99 和 C++89、C++11 @Adrian 对于 C 是 5.1.2.2.1。 好的 C99 5.1.22.1.1 说“它应该用 int 的返回类型定义” c++14882 3.6.1.1 说“它应该有一个 int 类型的返回类型”和 c+ +14882-2011 3.6.1.1 说“它应该有一个 int 类型的返回类型”所以@fefe 他们似乎明确定义为在 C 和 C++ 之间是相同的 【参考方案1】:

假设我们使用的是 Visual Studio 2012。

对于 C++ 程序,Visual Studio 允许将 void 指定为返回类型,即使 C++ 标准禁止这样做。根据标准,main() 必须在托管实现中返回 int

对于 C 程序,main() 允许任何返回类型,但返回 int 以外的其他内容会导致未指定的行为。例如,在 Visual Studio 2012 下,当程序在调试器中运行时,从double main() 返回0.0 会导致返回值0xcccccccc(请参阅In Visual Studio C++, what are the memory allocation representations?)。

【讨论】:

【参考方案2】:

C 标准不允许您返回除 int 或 void 之外的任何其他值——c 编译器专门测试 main 的签名以确保它兼容。

【讨论】:

C99(以及我在 C11 草案中看到的)没有提到 void。只有int 的返回类型被明确提到'它应以int 的返回类型定义',但不幸的是句子结束'或以其他一些实现定义的方式'(5.1.2.2.1)跨度> 由于 void return 5.1.2.2.1 的评论而被否决,没有提及 void return @DanielFischer:我认为“以其他实现定义的方式”是指参数及其类型,而不是返回类型。 @dreamlax 我相信这就是目的。但就我对英语的了解而言,它可以被解读为允许任意实现定义的类型。我看到它是这样争论的。不幸的是,intonly 允许的返回类型(对于托管实现)并没有完全明确。【参考方案3】:

C 标准从未提及此_start 函数;我也不相信 C++ 会这样做。

在 1999 年 ISO 标准之前的 C 中,如果执行到达 main() 的末尾而不执行 return 语句,或者执行未指定值的 return 语句,则“返回终止状态到主机环境是未定义的”。在实践中,我见过这样的程序返回状态 1(失败)或内存中的某个任意值(例如调用的最后一个函数的结果)的实现。

1999 ISO C 标准改变了这一点:“到达终止 ma​​in 函数的 返回值 0”。这符合至少自 1998 年第一个 ISO C++ 标准以来 C++ 的规则。

(作为一种风格,我更喜欢在main 的末尾有一个显式的return 0;,即使它不是严格要求的。这与int 以外的main 函数一致,并且它为 C99 之前的 C 编译器提供更好的可移植性。)

所有这些都假定main 定义为返回类型int。这是 C 标准专门支持的唯一类型(int main(void)int main(int argc, char *argv[]) 或等效),但(托管)实现可能支持其他实现定义的定义。 C90 标准没有明确涵盖这种情况,但 C99 表示,“如果返回类型与 int 不兼容,则返回到宿主环境的终止状态是未指定的。”

C++ 标准有点不同。对于托管实现,main必须定义为返回int。参数是实现定义的,但必须支持两种标准形式的 C。

对于 C 或 C++ 中的托管实现,我知道没有充分的理由使用 int 以外的返回类型定义 main。只需使用两个标准定义之一,就不会出现问题。

对于“独立实现”,“程序调用的函数的名称和类型 启动是实现定义的”。因此入口点可能会合法地返回void或其他东西,甚至可能不会被称为main。请注意,“独立实现”是“其中可能发生C程序执行的”没有任何 操作系统的好处”,通常是嵌入式系统。

【讨论】:

在该定义下,系统内核开发是否也算作“独立实现”?当然,如果操作系统内核到达入口点函数的末尾,那你就有问题了…… @MichaelKjörling:可能。在实践中,如果实现者说它是“独立的”(并且符合独立实现的较弱要求),则实现是“独立的”。 @KeithThompson:在 C99 之前,如果执行到达 main() 的末尾而不执行 return 语句,或者执行没有指定值的 return 语句,则“终止状态返回到主机环境未指定”不是未定义。 @PravasiMeet:您的报价来源是什么? C90 标准第 5.1.2.2.3 节说:“如果主函数执行一个没有指定值的返回,则返回给宿主环境的终止状态是 undefined。” (强调)当然“未指定”会更有意义。【参考方案4】:

如果main 的返回类型不是int,则返回值是实现定义的。 简而言之,对于main,允许实现与int 具有不同的返回类型,但已知的实现都不支持int 以外的任何东西。 理想情况下,您需要参考您的平台和编译器的文档以查看它定义的确切行为,因为标准允许它具有灵活性。

参考:

C++03 标准:

3.6.1 主函数[basic.start.main]

实现不应预定义主要功能。该功能不得重载。 它的返回类型应该是 int 类型,否则它的类型是实现定义的。所有实现都应允许以下两种 main 定义:

int main() /* ... */

int main(int argc, char* argv[]) /* ... */

.....

【讨论】:

这不是说它必须有一个int返回类型,但除此之外它可以接受任何参数,只要实现允许没有参数和argc/argv (即返回类型int,但main函数的类型是实现定义的)。我在等咖啡安定下来,所以也许我没有任何意义......【参考方案5】:

C 的标准实现期望 main 返回 int,因为它在 C 标准中是这样定义的。返回 int 以外的东西(或与 int 兼容的类型)通常会导致未定义的行为——这意味着无法知道会发生什么。

但是,C 也有非标准实现,例如,Plan 9 操作系统使用void main(),here 是其实用程序的源代码列表。 Plan 9 C 代码与 K&R、ANSI、C99 或 C11 有很大不同。 Here's 解释 Plan 9 如何使用 C 语言的链接。

【讨论】:

【参考方案6】:

如果main 不返回int,那么您的程序格式错误并且行为未定义。任何事情都有可能发生。您的程序可能会崩溃,或者它可能会像没有任何问题一样运行。

假设main 返回的不是int,并且您的编译器和链接器允许生成程序。不过,来电者并不知道这一点。如果调用者期望返回的int 值在 EAX (Intel) 寄存器中返回,那么它将读取该值以确定main 的返回值。如果您的错误main 在那里存储了float 值,那么它将被解释为int。 (这并不意味着它会被截断。这意味着构成浮点值布局的位将改为构成int。)如果您的错误main返回void,那么它没有'不在预期的寄存器中存储任何内容,因此调用者将获得之前存储在该寄存器中的任何值。

如果你的main 返回了一些类型,它希望存储调用者没有为它保留内存的某个地方(例如一个大结构),那么它最终会覆盖其他东西,也许是对清理很重要的东西关闭程序,导致程序崩溃。

【讨论】:

如何在 EAX 中存储浮点数? @KerrekSB - 好问题。虽然,在 80486 之前,它相对常见。毕竟,浮点数只是您使用特殊规则来操作的 32 位内容。 浮点数是否在寄存器中返回,@Kerrek?我不知道。在我在回答中描述的想象场景中,main 确实 - 不知何故 - 在调用者期望 int 去的地方存储了一个浮点数。行为是未定义的,所以我可以描述我想要的任何奇怪的工作方式! @RobKennedy:浮点数通常在 FPU 的浮点寄存器中返回(例如 80387,或者可能是现代 MMX 的东西)。 x86 cdeclST0 中返回一个浮点数。新的 SIMD 寄存器仅用于 x64,其中XMM0 包含 FP 返回值。【参考方案7】:

在 C++ 中,如果从 main() 返回 int 以外的任何内容将是编译错误:

error: ‘::main’ must return ‘int’

在 C 语言中这是一个警告,您会得到一个浮点数,它被重新解释为 int:例如,2.1F 将被重新解释为 224。

【讨论】:

仅供参考,gcc 默认不发出任何警告。 @shinkou 我刚试过 gcc - 它给了我warning: return type of ‘main’ is not ‘int’ 我在 gcc 版本 4.5.2 (64bit) btw 上测试过。【参考方案8】:

该函数将返回一个实现定义的值。例如,在 C++ 中,main 隐式返回 0。在这种void main 的情况下,这将简单地由_start 返回。然而,几乎没有任何实现允许任意返回类型——它被嵌入操作系统中,进程以整数值退出。

【讨论】:

以上是关于如果 main() 不返回 int 值会怎样?的主要内容,如果未能解决你的问题,请参考以下文章

C++14 中 main() 的合法定义

为啥我的数组值会发生变化? [复制]

arm程序退出死循环

python函数使用参数技巧笔记

为啥 int main() 编译?

从lua的c源码了解lua栈结构和函数调用流程