76

C 中 main 函数的有效签名到底是什么?我知道:

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

还有其他有效的吗?

4

5 回答 5

81

C11标准明确提到了这两个:

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

尽管它确实在以下脚注中提到了“或等效”一词:

因此,int可以替换为typedef定义为 的名称int,或者类型argv可以写为char ** argv,依此类推。

此外,它还提供了更多(实现定义的)可能性。

相关文本(部分5.1.2.2.1,但此特定方面与 未更改C99)指出:

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

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

或带有两个参数(这里称为argcand argv,尽管可以使用任何名称,因为它们对于声明它们的函数是本地的):

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

或同等学历; 或以其他一些实现定义的方式。

如果声明了它们,则main函数的参数应遵守以下约束:

  • 的值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和字符串应可由程序修改,并在程序启动和程序终止之间保留其最后存储的值。argvargv

请注意,这是针对托管环境的,即您通常在 C 程序中看到的环境。如同一标准所述,独立环境(例如嵌入式系统)的限制要小得多5.1.2.1

在独立环境中(C 程序的执行可能在没有操作系统的任何好处的情况下发生),程序启动时调用的函数的名称和类型是实现定义的。除了第 4 节要求的最小集合之外,独立程序可用的任何库设施都是实现定义的。

于 2010-01-21T09:50:28.603 回答
24

标准 C

对于托管环境(这是正常环境),C99 标准说:

5.1.2.2.1 程序启动

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

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

或带有两个参数(这里称为argcand argv,尽管可以使用任何名称,因为它们对于声明它们的函数是本地的):

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

或同等学历; 9)或以其他一些实现定义的方式。

9)因此,int可以用定义为 的 typedef 名称替换int,或者argv可以写为的类型char **argv,以此类推。

C11 和 C18 标准与 C99 标准基本相同。

标准 C++

C++98 标准说:

3.6.1 主函数[basic.start.main]

1 程序应包含一个名为 main 的全局函数,它是程序的指定开始。[...]

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

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

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

C++ 标准明确规定“它 [主函数] 的返回类型应为 type int,否则它的类型是实现定义的”,并且需要与 C 标准相同的两个签名。因此,C++ 标准直接不允许使用“void main()”,尽管它无法阻止不符合标准的实现允许替代方案(也无法阻止符合标准的实现允许替代方案作为标准的扩展)。

C++03、C++11、C++14 和 C++17 标准与 C++98 基本相同。

通用扩展

传统上,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[]);

或者,mainandwmain函数可以声明为返回void(无返回值)。如果您声明mainwmain返回 void,则无法使用 return 语句将退出代码返回给父进程或操作系统。main要在或wmain声明为时返回退出代码void,您必须使用该exit函数。

我不清楚当一个程序退出时会发生什么(什么退出代码返回给父级或 o/s)void main()——而且 MS 网站也保持沉默。

有趣的是,MS 没有规定main()C 和 C++ 标准要求的两个参数版本。它只规定了一个三参数形式,其中第三个参数是char **envp,一个指向环境变量列表的指针。

Microsoft 页面还列出了其他一些替代方案——wmain()它采用宽字符串等等。

此页面的 Microsoft VS 2005 版本并未void main()作为替代方案列出。Microsoft VS 2008 以后的版本可以。

int main()一样的int main(void)吗?

有关详细分析,请参阅我对What should main()return in C and C++的回答的结尾。(似乎我曾经认为这个问题提到了 C++,尽管它没有也从来没有这样做过。在 C++ 中,int main()andint main(void)int main()是惯用的 C++ 之间没有区别。)

在 C 中,这两种表示法之间存在差异,但您只在深奥的情况下才会注意到它。具体来说,如果您main()从自己的代码中调用该函数,则会有所不同,您可以在 C 中执行此操作,而不允许在 C++ 中执行此操作。

int main()表示法不提供 的原型main(),但这仅在您递归调用它时才重要。使用int main(),您可能稍后(在同一个函数或另一个函数中)编写int rc = main("absolute", "twaddle", 2):并且正式地编译器不应该抱怨拒绝编译代码的程度,尽管它可能会合理地抱怨(警告您)它(并使用-Werrorwith GCC 会将警告转换为错误)。如果你使用int main(void),随后的调用main()应该会产生一个错误——你说这个函数没有参数但试图提供三个。当然,main()在声明或定义它之前,你不能合法地调用它(除非你仍在使用 C90 语义)——并且实现没有声明一个原型main(). NB:C11 标准在不同的例子中说明了两者int main()——int main(void)两者在 C 中都是有效的,尽管它们之间存在细微的差别。

于 2010-11-25T04:31:49.317 回答
8

http://en.wikipedia.org/wiki/Main_function_(programming)#C_and_C.2B.2B

除了通常int main(int argc, char *argv[])的和 POSIX之外int main(int argc, char **argv, char **envp),Mac OS X 上还支持

int main(int argc, char* argv[], char* envp[], char* apple[]);

当然,它仅限于 Mac。

在 Windows 上有

int wmain(int argc, wchar_t* argv[], wchar_t* envp[]);

作为 Unicode(实际上是宽字符)变体。当然也有WinMain

于 2010-01-21T10:06:45.963 回答
8

POSIX 支持execve(),而后者又支持

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

添加的参数是环境,即NAME=VALUE 形式的字符串数组。

于 2010-01-21T09:53:43.217 回答
4
int main(void)

在某些操作系统(例如,Windows)下也是有效的:

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

whereenvp提供环境,否则可通过getenv()

于 2010-01-21T09:52:24.170 回答