在C和C++中定义main()函数的正确(最有效)方法是什么?int main()或void main()-为什么?那争论呢?如果int main(),则返回1或0?


这个问题有很多重复之处,包括:

C的main()函数的有效签名是什么?main()函数的返回类型void main()和int main()之间的区别?main()在C中的签名++main()的正确声明是什么?-对于C++,确实有一个非常好的答案。C中main()函数的样式C中main()方法的返回类型C中的int main()与void main()

相关:

C++-int main(int argc,char**argv)C++-int main(int argc,char*argv[])char*envp[]作为main()的第三个参数是否可移植?int main()函数必须在所有编译器中返回值吗?为什么C和C++中main()函数的类型留给用户定义?为什么int main(){}编译?C++14中main()的合法定义?


当前回答

请记住,即使您返回的是int,某些OS(Windows)也会将返回的值截断为单个字节(0-255)。

其他回答

注意,C和C++标准定义了两种实现:独立的和托管的。

C90托管环境

允许的表单1:

int main (void)
int main (int argc, char *argv[])

main (void)
main (int argc, char *argv[])
/*... etc, similar forms with implicit int */

评论:

前两个被显式声明为允许的形式,其他的被隐式允许,因为C90允许返回类型和函数参数为“隐式int”。不允许使用其他形式。

C90独立环境

允许使用任何形式或名称的main 2。

C99托管环境

允许的表单3:

int main (void)
int main (int argc, char *argv[])
/* or in some other implementation-defined manner. */

评论:

C99删除了“隐式int”,因此main()不再有效。

引入了一个奇怪的、模棱两可的句子“或以某种其他实现定义的方式”。这可以被解释为“intmain()的参数可能不同”或“main可以有任何实现定义的形式”。

一些编译器选择以后一种方式解释标准。可以说,人们不能轻易地通过引用标准本身来说明他们不符合标准,因为它是模棱两可的。

然而,允许main()的完全野生形式可能不是(?)这个新句子的意图。C99的基本原理(非规范性)意味着该语句引用了int main 4的附加参数。

然而,托管环境程序终止部分继续讨论main不返回int 5的情况。尽管该部分对于如何声明main并不是规范性的,但它肯定意味着即使在托管系统上,main也可以以完全实现定义的方式声明。

C99独立环境

允许使用任何形式或名称的main。

C11托管环境

允许的表单7:

int main (void)
int main (int argc, char *argv[])
/* or in some other implementation-defined manner. */

C11独立环境

允许使用任何形式或名称的main。


注意,在上述任何版本中,int main()从未被列为C的任何托管实现的有效形式。在C中,与C++不同,()和(void)有不同的含义。前者是一种过时的特征,可以从语言中删除。参见C11未来语言方向:

6.11.6函数声明器使用带有空括号的函数声明符(而不是原型格式参数类型声明符)是一种过时的特性。


C++03托管环境

允许的表单9:

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

评论:

注意第一种形式中的空括号。在这种情况下,C++和C是不同的,因为在C++中,这意味着函数不带参数。但在C中,这意味着它可以采用任何参数。

C++03独立环境

启动时调用的函数的名称是实现定义的。如果它被命名为main(),它必须遵循所述的格式10:

// implementation-defined name, or 
int main ()
int main (int argc, char *argv[])

C++11托管环境

允许的表单11:

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

评论:

标准文本已更改,但含义相同。

C++11独立环境

启动时调用的函数的名称是实现定义的。如果它被命名为main(),它必须遵循所述的形式12:

// implementation-defined name, or 
int main ()
int main (int argc, char *argv[])

工具书类

ANSI X3.159-1989 2.1.2.2托管环境。“程序启动”

程序启动时调用的函数名为main。这个实现没有声明此函数的原型。应为定义为返回类型为int且没有参数:

int main(void) { /* ... */ } 

或具有两个参数(这里称为argc和argv,但可以使用任何名称,因为它们是本地的声明它们的函数):

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

ANSI X3.159-1989 2.1.2.1独立环境:

在独立的环境中(C程序执行可能需要没有任何操作系统好处的地方)、名称和类型在程序启动时调用的函数的实现是定义的。

ISO 9899:1999 5.1.2.2托管环境->5.1.2.2.1程序启动

程序启动时调用的函数名为main。这个实现没有声明此函数的原型。应为定义为返回类型为int且没有参数:

int main(void) { /* ... */ } 

或具有两个参数(这里称为argc和argv,但可以使用任何名称,因为它们是本地的声明它们的函数):

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

或同等产品;9) 或在定义的某些其他实现中方式

国际标准编程语言-C的基本原理,修订版5.10。5.1.2.2托管环境-->5.1.2.2.1程序启动

main参数的行为,以及exit、main和atexit的交互作用(见§7.20.4.2)已被编入法典,以抑制argv表示中的一些不必要的变化字符串,以及main返回值的含义。

argc和argv作为main参数的规范承认了广泛的先前实践。argv[argc]必须是空指针,以便为列表末尾提供冗余检查,这也是基于常见的做法。

main是唯一一个可以用零或两个参数声明的函数。(其他函数的参数数量必须在调用和定义之间完全匹配。)这种特殊情况只是认识到当程序不访问程序参数字符串时,将参数保留为main的普遍做法。尽管许多实现支持两个以上的主要论点,但标准既不支持也不禁止这种做法;用三个参数定义main的程序并不严格符合(见§J.5.1.)。

ISO 9899:1999 5.1.2.2托管环境-->5.1.2.2.3程序终止

如果主函数的返回类型是与int兼容的类型,那么从初始调用到主函数的一个返回就相当于用主函数返回的值作为其参数调用退出函数;11) 到达终止主函数的}返回值0。如果返回类型与int不兼容,则返回到主机环境的终止状态未指定。

ISO 9899:1999 5.1.2.1独立环境

在一个独立的环境中(在这种环境中,C程序的执行可能没有任何操作系统的好处),程序启动时调用的函数的名称和类型是由实现定义的。

ISO 9899:2011 5.1.2.2托管环境->5.1.2.2.1程序启动

本节与上述C99节相同。

ISO 9899:1999 5.1.2.1独立环境

本节与上述C99节相同。

ISO 14882:2003 3.6.1主要功能

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

int main() { /* ... */ }

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

ISO 14882:2003 3.6.1主要功能

它定义了独立环境中的程序是否需要定义主功能。

ISO 14882:2011 3.6.1主要功能

实现不应预先定义主功能。该功能不应过载。它应该具有int类型的返回类型,否则它的类型是实现定义的。所有实施应允许两者-返回int和-返回int的(int,指向指向char的指针)函数作为主要类型(8.3.5)。

ISO 14882:2011 3.6.1主要功能

本节与上述C++03节相同。

操作系统可以使用返回值来检查程序是如何关闭的。

返回值0通常意味着大多数操作系统(我无论如何都能想到的操作系统)正常。

当您自己调用进程时,也可以检查它,看看程序是否退出并正确完成。

这不仅仅是一个编程惯例。

在C和C++中定义main()函数的正确(最有效)方法是什么?int main()或void main()-为什么?

这些词“(最有效)”并不能改变问题。除非您处于独立的环境中,否则有一种普遍正确的方法来声明main(),那就是返回int。

main()在C和C++中应该返回什么?

一个int,纯粹而简单。它不仅仅是“应该返回什么”,而是“必须返回什么”。main()当然是其他人调用的函数。您无法控制调用main的代码。因此,必须使用类型正确的签名声明main以匹配其调用者。你在这件事上没有任何选择。你不必问自己什么效率更高或更低,什么风格更好或更差,或者诸如此类的问题,因为答案已经由C和C++标准完美地定义了。跟着他们就行了。

如果int main(),则返回1或0?

0表示成功,非零表示失败。同样,这不是你需要(或得到)选择的东西:它是由你应该遵守的接口定义的。

接受的答案似乎是针对C++的,所以我想添加一个与C相关的答案,这在一些方面有所不同。ISO/IEC 9899:1989(C90)和ISO/IEC 9899:1999(C99)之间也进行了一些更改。

main()应声明为:

int main(void)
int main(int argc, char **argv)

或同等产品。例如,int main(int argc,char*argv[])等同于第二个。在C90中,int返回类型可以省略,因为它是默认值,但在C99和更高版本中,不能省略int返回类型。

如果实现允许,main()可以用其他方式声明(例如,int main(int argc,char*argv[],char*envp[])),但这会使程序实现被定义,不再严格遵守。

标准为返回定义了三个严格一致的值(即,不依赖于实现定义的行为):0和EXIT_SUCCESS表示成功终止,EXIT_FAILURE表示失败终止。任何其他值都是非标准的,并定义了实现。在C90中,main()必须在末尾有一个显式返回语句,以避免未定义的行为。在C99和更新版本中,可以省略main()中的return语句。如果您这样做了,main()完成了,则会有一个隐式返回0。

最后,从标准的角度来看,从C程序递归调用main()并没有错。

ISO现在要求C和C++都使用“int”作为“main”的返回类型。

这两种语言以前都允许隐式“int”,而“main”的声明没有任何返回类型。事实上,C++的第一个外部版本(1985年2月发布的“cfront”E版),用自己的语言编写,声明为“main”,没有任何返回类型。。。但返回了一个整数值:错误数或127,以较小者为准

至于返回什么的问题:C和C++的ISO标准与POSIX标准同步工作。对于符合POSIX标准的任何托管环境,(1) 126为OS的外壳保留以指示不可执行的实用程序,(2) 127为OS的外壳保留,(3) 公用设施的退出值在逐个公用设施的基础上单独列出,(4) 调用外壳外部的实用程序的程序应该为它们自己的出口使用类似的值,(5) 值128和以上用于指示由于接收信号而导致的终止,(6) 值1-125表示故障,(7) 值0表示成功。

在C和C++中,值EXIT_SUCCESS和EXIT_FAILURE用于处理最常见的情况:用于报告成功或仅报告一般失败的程序。它们可以但不必分别等于0和1。

这意味着,如果您希望程序为不同的故障模式或状态指示返回不同的值,同时继续使用这两个常量,您可能必须首先确保附加的“故障”或“状态”值严格位于max(EXIT_SUCCESS,EXIT_failure)和126之间(并希望两者之间有足够的空间),并保留EXIT_FAILURE以标记通用或默认故障模式。

否则,如果你不打算使用常量,那么你应该按照POSIX的要求去做。

对于在独立环境或不符合POSIX的主机上使用的程序,我只能说以下几点:

我已经编写了独立的程序——作为自定义运行时系统上的多线程程序(以及其他一切的自定义工具库)。我遵循的一般规则是:(1) “main”运行前台进程,通常仅由启动、配置或初始化例程组成,但也可能包含用于连续操作的前台进程(如轮询循环),(2) “main”返回到无限睡眠和等待循环,(3) 未定义或使用“main”的返回值,(4) 后台进程单独运行,作为中断驱动和事件驱动线程,独立于“主”,仅在收到重置信号或其他线程时终止。。。或者简单地关闭对驱动线程的任何事件的监视。