Joe*_*oel 663 c c++ program-entry-point return-type return-value
main()
在C和C++中定义函数的正确(最有效)方法是什么- int main()
或void main()
- 为什么?如果int main()
那么return 1
或return 0
?
这个问题有很多重复,包括:
main()
函数的有效签名是什么?main()
函数void main()
和int main()
?main()
在C++中的签名main()
? - 对于C++,确实有一个非常好的答案.main()
C语言中的函数样式main()
C中的方法类型int main()
vs void main()
在C中有关:
wor*_*ad3 543
返回值main
应指示程序如何退出.正常退出通常由0返回值表示main
.异常退出通常通过非零返回来表示,但是没有关于如何解释非零代码的标准.另外,如其他人void main()
所述,C++标准明确禁止,不应使用.有效的C++ main
签名是:
int main()
Run Code Online (Sandbox Code Playgroud)
和
int main(int argc, char* argv[])
Run Code Online (Sandbox Code Playgroud)
这相当于
int main(int argc, char** argv)
Run Code Online (Sandbox Code Playgroud)
值得注意的是,在C++中,int main()
可以保留没有返回值,此时它默认返回0.对于C99程序也是如此.是否return 0;
应该省略是有争议的.有效的C程序主要签名的范围要大得多.
此外,效率不是main
功能的问题.它只能根据C++标准输入和保留一次(标记程序的启动和终止).对于C,情况不同并且main()
允许重新进入,但应该避免.
Chr*_*ung 162
接受的答案似乎是针对C++的,所以我想我会添加一个与C相关的答案,这在某些方面有所不同.
ISO/IEC 9899:1989(C90):
main()
应声明为:
int main(void)
int main(int argc, char **argv)
Run Code Online (Sandbox Code Playgroud)
或同等学历.例如,int main(int argc, char *argv[])
相当于第二个.此外,int
返回类型可以省略,因为它是默认值.
如果一个实现允许它,main()
可以用其他方式声明,但这使得程序实现被定义,并且不再严格符合.
该标准定义了3个严格符合的返回值(即,不依赖于实现定义的行为):0
以及EXIT_SUCCESS
成功终止和EXIT_FAILURE
不成功终止.任何其他值都是非标准的并且实现已定义.main()
必须return
在最后有一个明确的声明,以避免未定义的行为.
最后,从标准的角度来看,main()
从程序调用没有任何错误.
ISO/IEC 9899:1999(C99):
对于C99,一切都与上述相同,除了:
int
返回类型不能省略.main()
.如果你这样做,并且main()
完成了,那就是隐含的return 0
.Jon*_*ler 111
对于托管环境(这是正常的环境),C11标准(ISO/IEC 9899:2011)说:
5.1.2.2.1程序启动
在程序启动时调用的函数被命名
main
.该实现声明此函数没有原型.它应定义为返回类型int
且没有参数:Run Code Online (Sandbox Code Playgroud)int main(void) { /* ... */ }
或者有两个参数(这里称为
argc
和argv
,虽然可以使用任何名称,因为它们是声明它们的函数的本地名称):Run Code Online (Sandbox Code Playgroud)int main(int argc, char *argv[]) { /* ... */ }
或同等学历; 10)或以某种其他实现定义的方式.
如果声明它们,main函数的参数应遵循以下约束:
- 值
argc
应为非负值.argv[argc]
应为空指针.- 如果值
argc
大于零,则argv[0]
通过argv[argc-1]
包含的数组成员应包含指向字符串的指针,这些指针在程序启动之前由主机环境给出实现定义的值.目的是在程序启动之前从托管环境中的其他地方向程序提供信息.如果主机环境不能提供大写和小写字母的字符串,则实现应确保以小写形式接收字符串.- 如果值
argc
大于零,则指向的字符串argv[0]
表示程序名称;argv[0][0]
如果程序名不能从主机环境获得,则应为空字符.如果值argc
大于1,则argv[1]
through 指向的字符串argv[argc-1]
表示程序参数.- 数组指向的参数
argc
和argv
字符串argv
应由程序修改,并在程序启动和程序终止之间保留它们最后存储的值.10)因此,
int
可以替换为定义为的typedef名称int
,或者argv
可以写为 的类型char **argv
,依此类推.
返回的值main()
以实现定义的方式传输到"环境".
5.1.2.2.3程序终止
1如果
main
函数的返回类型是兼容的类型int
,则从初始调用main
函数返回到函数等效于调用exit
函数返回的main
函数作为其参数; 11)到达该}
终止main
函数返回值0.如果返回类型不兼容int
,则返回到主机环境的终止状态未指定.11)根据6.2.4,具有自动存储持续时间的物体的寿命
main
将在前一种情况下结束,即使它们在后者中没有.
请注意,这0
被命名为"成功".如果您愿意,可以使用EXIT_FAILURE
和EXIT_SUCCESS
来<stdlib.h>
,但是0已经很好建立了,所以也是1.参见大于255的退出代码 - 可能吗?.
在C89中(因此在Microsoft C中),没有声明如果main()
函数返回但未指定返回值会发生什么; 因此它导致未定义的行为.
7.22.4.4
exit
功能5最后,控制权返回给主机环境.如果值
status
为零或EXIT_SUCCESS
,则返回状态成功终止的实现定义形式.如果值status
是EXIT_FAILURE
,地位的实现定义的形式成功终止返回.否则返回的状态是实现定义的.
C++ 11标准(ISO/IEC 14882:2011)说:
3.6.1主要功能[basic.start.main]
1程序应包含一个名为main的全局函数,它是程序的指定开始.[...]
2实现不应预定义主函数.此功能不应过载.它应该具有int类型的返回类型,否则其类型是实现定义的.所有实现都应允许以下两个主要定义:
Run Code Online (Sandbox Code Playgroud)int main() { /* ... */ }
和
Run Code Online (Sandbox Code Playgroud)int main(int argc, char* argv[]) { /* ... */ }
后一种形式
argc
应该是从运行程序的环境传递给程序的参数数量.如果argc
是非零这些参数应被供应argv[0]
通过argv[argc-1]
作为指针指向空终止多字节串的初始字符(NTMBSs)(17.5.2.1.4.2)和argv[0]
应为指针NTMBS的初始字符,表示用来名称调用程序或""
.值argc
应为非负值.值argv[argc]
应为0. [注意:建议在之后添加任何其他(可选)参数argv
. - 尾注]3该功能
main
不得在程序中使用.链接(3.5)main
是实现定义的.[...]5main中的return语句具有离开main函数(销毁具有自动存储持续时间的任何对象)并
std::exit
使用返回值作为参数进行调用的效果.如果控制到达main的末尾而没有遇到return语句,则效果就是执行Run Code Online (Sandbox Code Playgroud)return 0;
C++标准明确地说"它[主函数]应该具有类型的返回类型int
,但是其类型是实现定义的",并且需要与C标准相同的两个签名作为选项支持.因此,C++标准直接不允许'void main()',尽管没有什么可以阻止非标准实现允许替代.请注意,C++禁止用户调用main
(但C标准没有).
在C++ 11标准中有一段§18.5 开始和终止,与§7.22.4.4中的段落相同C11标准中的exit
功能(如上所述),除了脚注(它只是记录EXIT_SUCCESS
和EXIT_FAILURE
定义) in <cstdlib>
).
传统上,Unix系统支持第三种变体:
int main(int argc, char **argv, char **envp) { ... }
Run Code Online (Sandbox Code Playgroud)
第三个参数是一个以null结尾的字符串指针列表,每个字符串都是一个环境变量,它有一个名称,一个等号和一个值(可能是空的).如果你不使用它,你仍然可以通过' extern char **environ;
' 进入环境.很长一段时间,它没有声明它的标题,但POSIX 2008标准现在要求它被声明<unistd.h>
.
这被C标准认可为附录J中记录的共同扩展:
J.5.1环境参数
1在托管环境中,main函数接收第三个参数,
char *envp[]
该参数指向以null结尾的指针数组char
,每个指针指向一个字符串,该字符串提供有关此程序执行环境的信息(5.1. 2.2.1).
在微软VS 2010的编译器是有趣的.该网站说:
main的声明语法是
Run Code Online (Sandbox Code Playgroud)int main();
或者,可选地,
Run Code Online (Sandbox Code Playgroud)int main(int argc, char *argv[], char *envp[]);
或者,可以将
main
和wmain
函数声明为返回void
(无返回值).如果声明main
或wmain
返回void,则无法使用return语句将退出代码返回到父进程或操作系统.要在声明为main
或返回时返回退出代码,必须使用该函数.wmain
void
exit
我不清楚当一个程序void main()
退出时会发生什么(返回父代或操作系统的退出代码)- 而且MS网站也是静默的.
有趣的是,MS没有规定main()
C和C++标准所要求的双参数版本.它只规定了一个三参数形式,其中第三个参数是char **envp
指向环境变量列表的指针.
Microsoft页面还列出了一些其他选项 - wmain()
它们需要广泛的字符串,还有更多.
此页面的Microsoft Visual Studio 2005版本不作为替代列出.Microsoft Visual Studio 2008以后的版本可以.void main()
如前所述,上述要求适用于托管环境.如果您正在使用独立环境(这是托管环境的替代方案),那么标准就更不用说了.对于独立环境,不需要调用程序启动时调用的函数,main
并且对其返回类型没有约束.标准说:
5.1.2执行环境
定义了两个执行环境:独立和托管.在这两种情况下,当执行环境调用指定的C函数时,程序启动发生.具有静态存储持续时间的所有对象应在程序启动之前初始化(设置为其初始值).否则,未指定这种初始化的方式和时间.程序终止将控制权返回给执行环境.
5.1.2.1独立环境
在独立环境中(可以在没有操作系统任何好处的情况下执行C程序),程序启动时调用的函数的名称和类型是实现定义的.除了第4节要求的最小集合之外,任何可用于独立程序的库设施都是实现定义的.
程序终止在独立环境中的影响是实现定义的.
对第4条一致性的交叉引用是指:
5 严格符合的程序应仅使用本国际标准中规定的语言和库的特征.3)它不应产生依赖于任何未指定,未定义或实现定义的行为的输出,并且不得超过任何最小实现限制.
6两种形式的符合要求的实施是托管和独立的.一个符合托管实施应当接受任何严格符合程序.甲符合独立执行应接受任何严格符合程序,其中使用的库条款(第7节)中指定的功能被限制在标准报头的内容
<float.h>
,<iso646.h>
,<limits.h>
,<stdalign.h>
,<stdarg.h>
,<stdbool.h>
,<stddef.h>
,<stdint.h>
,和<stdnoreturn.h>
.符合实现的实现可能具有扩展(包括附加库函数),前提是它们不会改变任何严格符合程序的行为.4)7 符合要求的程序是符合要求的程序可接受的程序.5)
3)严格符合程序可以使用条件特征(见6.10.8.3),前提是使用相关的宏通过适当的条件包含预处理指令来保护.例如:
Run Code Online (Sandbox Code Playgroud)#ifdef __STDC_IEC_559__ /* FE_UPWARD defined */ /* ... */ fesetround(FE_UPWARD); /* ... */ #endif
4)这意味着符合要求的实施不保留本国际标准中明确保留的标识符以外的标识符.
5)严格符合程序旨在在符合要求的实现中最大程度地便携.合规程序可能依赖于符合实现的非便携特征.
值得注意的是,实际定义任何函数的独立环境所需的唯一标头是<stdarg.h>
(甚至可能是 - 通常只是宏).
正如C标准同时承认托管和独立环境一样,C++标准也是如此.(引自ISO/IEC 14882:2011.)
1.4实施合规[intro.compliance]
7定义了两种实现:托管实现和独立实现.对于托管实现,此国际标准定义了可用库集.独立实现是一种可以在没有操作系统的情况下执行的实现,并且具有包含某些语言支持库的实现定义的库集(17.6.1.3).
8符合要求的实现可能具有扩展(包括其他库函数),前提是它们不会改变任何格式良好的程序的行为.需要实现来诊断使用根据本国际标准格式不正确的扩展的程序.但是,这样做之后,他们就可以编译和执行这样的程序.
9每个实现都应包括标识其不支持的所有条件支持的构造的文档,并定义所有特定于语言环境的特征.3
3)该文档还定义了实现定义的行为; 见1.9.
17.6.1.3独立实施[合规]
定义了两种实现:托管和独立(1.4).对于托管实现,此国际标准描述了可用标头集.
独立实现具有实现定义的头集.该组至少应包括表16中所示的标题.
报头的提供的版本
<cstdlib>
应宣布至少功能abort
,atexit
,at_quick_exit
,exit
,和quick_exit
(18.5).此表中列出的其他标头应满足与托管实现相同的要求.表16 - 独立实现的C++头
Run Code Online (Sandbox Code Playgroud)Subclause Header(s) <ciso646> 18.2 Types <cstddef> 18.3 Implementation properties <cfloat> <limits> <climits> 18.4 Integer types <cstdint> 18.5 Start and termination <cstdlib> 18.6 Dynamic memory management <new> 18.7 Type identification <typeinfo> 18.8 Exception handling <exception> 18.9 Initializer lists <initializer_list> 18.10 Other runtime support <cstdalign> <cstdarg> <cstdbool> 20.9 Type traits <type_traits> 29 Atomics <atomic>
int main()
在C中使用怎么样?C11标准的标准§5.1.2.2.1显示了首选符号 - int main(void)
但标准中还有两个例子显示int main()
:§6.5.3.48和§6.7.6.320.现在,重要的是要注意,例子不是"规范的"; 它们只是说明性的.如果示例中存在错误,则它们不会直接影响标准的主要文本.也就是说,它们强烈表明预期的行为,因此如果标准包含int main()
在一个例子中,它表明int main()
不禁止,即使它不是首选符号.
6.5.3.4
sizeof
和_Alignof
运营商...
8示例3在此示例中,计算可变长度数组的大小并从函数返回:
Run Code Online (Sandbox Code Playgroud)#include <stddef.h> size_t fsize3(int n) { char b[n+3]; // variable length array return sizeof b; // execution time sizeof } int main() { size_t size; size = fsize3(10); // fsize3 returns 13 return 0; }
dmi*_*gov 59
我相信main()
应该返回EXIT_SUCCESS
或者EXIT_FAILURE
.它们的定义是stdlib.h
Lun*_*din 38
请注意,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 */
Run Code Online (Sandbox Code Playgroud)
评论:
前两个被明确声明为允许的形式,其他两个被隐式允许,因为C90允许返回类型和函数参数的"隐式int".不允许其他形式.
C90独立式环境
允许任何形式或名称的主要2.
C99托管环境
允许的表格3:
int main (void)
int main (int argc, char *argv[])
/* or in some other implementation-defined manner. */
Run Code Online (Sandbox Code Playgroud)
评论:
C99删除了"implicit int",因此main()
不再有效.
引入了一个奇怪的,含糊不清的句子"或其他一些实现定义的方式".这可以解释为" int main()
可以改变的参数"或"main可以具有任何实现定义的形式".
一些编译器选择以后一种方式解释标准.可以说,人们不能轻易地通过引用标准本身来说明它们并不严格遵守,因为它是模棱两可的.
然而,允许完全狂野的形式main()
可能(?)不是这个新句子的意图.C99基本原理(非规范性)意味着该句子指的是int main
4的附加参数.
然而,托管环境程序终止的部分继续争论主要不返回int 5的情况.虽然该部分不是规范主要声明的规范,但它肯定意味着即使在托管系统上也可以以完全实现定义的方式声明main.
C99独立环境
允许任何形式或名称的主要6.
C11托管环境
允许的表格7:
int main (void)
int main (int argc, char *argv[])
/* or in some other implementation-defined manner. */
Run Code Online (Sandbox Code Playgroud)C11独立环境
允许任何形式或名称的主要8.
请注意,int main()
在任何上述版本中,从未将其列为C的任何托管实现的有效表单.在C中,与C++ 不同,()
它(void)
具有不同的含义.前者是一种过时的功能,可以从语言中删除.见C11未来语言方向:
6.11.6函数声明符
使用带有空括号的函数声明符(不是prototype-format参数类型声明符)是一个过时的功能.
C++ 03托管环境
允许的表格9:
int main ()
int main (int argc, char *argv[])
Run Code Online (Sandbox Code Playgroud)
评论:
请注意第一种形式的空括号.在这种情况下,C++和C是不同的,因为在C++中这意味着该函数不带参数.但在C中,它意味着它可能需要任何参数.
C++ 03独立环境
启动时调用的函数名称是实现定义的.如果它被命名,main()
它必须遵循所述的表格10:
// implementation-defined name, or
int main ()
int main (int argc, char *argv[])
Run Code Online (Sandbox Code Playgroud)C++ 11托管环境
允许的表格11:
int main ()
int main (int argc, char *argv[])
Run Code Online (Sandbox Code Playgroud)
评论:
标准的文本已经改变,但它具有相同的含义.
C++ 11独立环境
启动时调用的函数名称是实现定义的.如果它被命名,main()
它必须遵循所述的表格12:
// implementation-defined name, or
int main ()
int main (int argc, char *argv[])
Run Code Online (Sandbox Code Playgroud)参考
ANSI X3.159-1989 2.1.2.2托管环境."程序启动"
程序启动时调用的函数名为main.该实现声明此函数没有原型.它应该使用int的返回类型定义,并且没有参数:
int main(void) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
或者有两个参数(这里称为argc和argv,虽然可以使用任何名称,因为它们是声明它们的函数的本地名称):
int main(int argc, char *argv[]) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)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) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
或者有两个参数(这里称为argc和argv,虽然可以使用任何名称,因为它们是声明它们的函数的本地名称):
int main(int argc, char *argv[]) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
或等效的; 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程序终止
如果main函数的返回类型是与int兼容的类型,则从初始调用返回main函数等效于调用exit函数,并将main函数返回的值作为其参数; 11)到达该函数
}
终止main函数返回值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() { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
和
int main(int argc, char* argv[]) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)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相同.
main()
在C89和K&R C中,未指定的返回类型默认为'int`.
return 1? return 0?
Run Code Online (Sandbox Code Playgroud)
如果不写入return语句int main()
,则{
默认情况下结束将返回0.
return 0
或return 1
将由父进程收到.在shell中它进入shell变量,如果你运行程序形成一个shell而不使用该变量,那么你不必担心返回值main()
.
请参阅如何获取主函数返回的内容?.
$ ./a.out
$ echo $?
Run Code Online (Sandbox Code Playgroud)
通过这种方式,您可以看到它是$?
接收返回值的最低有效字节的变量main()
.
在Unix和DOS脚本中,return 0
通常会返回成功和非零错误.这是Unix和DOS脚本使用的标准,用于查找程序发生的情况并控制整个流程.
请记住,即使您返回int,某些操作系统(Windows)也会将返回值截断为单个字节(0-255).
操作系统可以使用返回值来检查程序是如何关闭的。
在大多数操作系统中,返回值 0 通常表示 OK(我能想到的操作系统)。
当您自己调用进程时也可以检查它,看看程序是否正确退出并完成。
这不仅仅是一个编程约定。
归档时间: |
|
查看次数: |
319085 次 |
最近记录: |