标准 C — 托管环境
对于托管环境(这是正常环境),C11 标准 (ISO/IEC 9899:2011) 说:
5.1.2.2.1 程序启动
程序启动时调用的函数名为main
. 实现没有声明这个函数的原型。它应定义为返回类型int
且不带参数:
int main(void) { /* ... */ }
或带有两个参数(这里称为argc
and argv
,尽管可以使用任何名称,因为它们对于声明它们的函数是本地的):
int main(int argc, char *argv[]) { /* ... */ }
或同等学历; 10)或以其他一些实现定义的方式。
如果它们被声明,主函数的参数应遵守以下约束:
- 的值
argc
应为非负数。
argv[argc]
应为空指针。
- 如果 的值
argc
大于零,则argv[0]
通过
argv[argc-1]
inclusive 的数组成员应包含指向字符串的指针,这些指针在程序启动之前由宿主环境赋予实现定义的值。目的是从托管环境中的其他地方向程序提供在程序启动之前确定的信息。如果主机环境不能提供大写和小写字母的字符串,则实现应确保以小写形式接收字符串。
- 如果 的值
argc
大于零,则 指向的字符串argv[0]
代表程序名;argv[0][0]
如果主机环境中没有程序名,则应为空字符。如果 的值argc
大于 1,则argv[1]
through指向的字符串argv[argc-1]
表示程序参数。
- 数组所指向的参数
argc
和字符串应可由程序修改,并在程序启动和程序终止之间保留其最后存储的值。argv
argv
10)因此,int
可以替换为定义为 的 typedef 名称int
,或者argv
可以写为
的类型char **argv
,依此类推。
C99 或 C11 中的程序终止
从返回的值main()
以实现定义的方式传输到“环境”。
5.1.2.2.3 程序终止
1 如果main
函数的返回类型是与 兼容的类型int
,则从函数的初始调用返回main
相当于以exit
函数返回的值main
作为参数调用函数;11)到达}
终止
main
函数返回值0。如果返回类型与 不兼容int
,则返回到宿主环境的终止状态未指定。
11)根据 6.2.4,在前一种情况下声明了自动存储持续时间的对象的生命周期main
将结束,即使在后者中它们不会有。
请注意,这0
是强制性的“成功”。如果您愿意,可以使用EXIT_FAILURE
and EXIT_SUCCESS
from <stdlib.h>
,但 0 已确定,1 也是如此。另请参阅大于 255 的退出代码 — 可能吗?.
在 C89 中(因此在 Microsoft C 中),没有关于如果main()
函数返回但没有指定返回值会发生什么的声明;因此,它会导致未定义的行为。
7.22.4.4exit
功能
¶5 最后,控制权返回到主机环境。如果 的值为status
0 或,则返回成功终止EXIT_SUCCESS
状态的实现定义形式。如果值为 ,则返回状态未成功终止的实现定义形式。否则返回的状态是实现定义的。status
EXIT_FAILURE
标准 C++ — 托管环境
C++11 标准 (ISO/IEC 14882:2011) 说:
3.6.1 主函数[basic.start.main]
¶1 程序应包含一个名为 main 的全局函数,它是程序的指定开始。[...]
¶2 实现不应预定义主要功能。该功能不得重载。它应该有一个 int 类型的返回类型,否则它的类型是实现定义的。所有实现都应允许以下两种 main 定义:
int main() { /* ... */ }
和
int main(int argc, char* argv[]) { /* ... */ }
后一种形式argc
是从程序运行的环境传递给程序的参数数量。如果argc
不为零,则这些参数应作为指向以空结尾的多字节字符串 (NTMBS) (17.5.2.1.4.2) 的初始字符的指针提供,并且argv[0]
应是指向 NTMBS 的初始字符的指针,该名称表示用于调用程序或. 的值应为非负数。的值
应为 0。 [ 注意:建议在 . 之后添加任何其他(可选)参数。——尾注]argv[argc-1]
argv[0]
""
argc
argv[argc]
argv
¶3 该功能main
不得在程序中使用。的链接(3.5)main
是实现定义的。[...]
¶5 main 中的 return 语句具有离开 main 函数(销毁具有自动存储持续时间的任何对象)并std::exit
以返回值作为参数进行调用的效果。如果控制到达main的末尾没有遇到return语句,效果就是执行
return 0;
C++ 标准明确规定“它 [主函数] 应具有 type 的返回类型int
,否则其类型是实现定义的”,并且需要与 C 标准相同的两个签名作为选项支持。因此,C++ 标准直接不允许使用“void main()”,尽管它无法阻止允许替代方案的非标准实现。请注意,C++ 禁止用户调用main
(但 C 标准没有)。
C++11 标准中有一段 §18.5开始和结束,与§7.22.4.4中的exit
段落相同中)。EXIT_SUCCESS
EXIT_FAILURE
<cstdlib>
标准 C——通用扩展
传统上,Unix 系统支持第三种变体:
int main(int argc, char **argv, char **envp) { ... }
第三个参数是一个以空结尾的字符串指针列表,每个字符串都是一个环境变量,它有一个名称、一个等号和一个值(可能为空)。如果你不使用这个,你仍然可以通过' extern char **environ;
'进入环境。这个全局变量在 POSIX 中是唯一的,因为它没有声明它的标头。
这被 C 标准认可为通用扩展,记录在附件 J 中:
J.5.1 环境参数
¶1 在托管环境中,main 函数接收第三个参数 ,char *envp[]
它指向一个以空结尾的指针数组char
,每个指针都指向一个字符串,该字符串为程序的执行提供有关环境的信息(5.1. 2.2.1)。
微软 C
Microsoft VS 2010编译器很有趣。该网站说:
main 的声明语法是
int main();
或者,可选地,
int main(int argc, char *argv[], char *envp[]);
或者,main
andwmain
函数可以声明为返回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()
标准 C — 独立环境
如前所述,上述要求适用于托管环境。如果您使用的是独立环境(这是托管环境的替代方案),那么标准就没有什么可说的了。对于独立环境,不需要调用在程序启动时调用的函数,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),只要使用相关宏的适当的条件包含预处理指令保护使用。例如:
#ifdef __STDC_IEC_559__ /* FE_UPWARD defined */
/* ... */
fesetround(FE_UPWARD);
/* ... */
#endif
4)这意味着一个符合要求的实现除了在本国际标准中明确保留的标识符外,不保留标识符。
5)严格符合的程序旨在最大限度地在符合的实现中移植。符合标准的程序可能取决于符合标准的实现的不可移植特性。
值得注意的是,实际定义任何函数的独立环境所需的唯一标头是<stdarg.h>
(甚至那些可能——而且通常是——只是宏)。
标准 C++ — 独立环境
正如 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++ 头文件
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 显示了首选符号 - <code>int main(void) - 但标准中也有两个示例显示int main()
:§6.5.3.4 ¶8和§6.7.6.3 ¶ 20 . 现在,重要的是要注意示例不是“规范的”;它们只是说明性的。如果示例中有错误,它们不会直接影响标准的正文。也就是说,它们强烈地表明了预期的行为,所以如果标准包含int main()
在一个例子中,它表明这int main()
是不被禁止的,即使它不是首选的符号。
6.5.3.4sizeof
和_Alignof
运算符
…</p>
¶8 示例 3 在此示例中,计算可变长度数组的大小并从函数返回:
#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;
}